mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-02 03:20:09 +08:00
Support most dialogs
Better JS->Go object mapping Implement Go->JS callback mechanism Rename `window.runtime` -> `window.wails` to better reflect the Go API
This commit is contained in:
parent
226572a1df
commit
73b08a45de
@ -22,8 +22,16 @@ Informal and incomplete list of things needed in v3.
|
||||
- [x] Same Window
|
||||
- [ ] Other Window
|
||||
- [ ] Dialogs
|
||||
- [x] Info
|
||||
- [x] Warning
|
||||
- [x] Error
|
||||
- [x] Question
|
||||
- [x] OpenFile
|
||||
- [ ] SaveFile
|
||||
- [ ] Events
|
||||
- [ ] Screens
|
||||
- [x] Clipboard
|
||||
- [ ] Application
|
||||
- [ ] Create `.d.ts` file
|
||||
|
||||
## Templates
|
||||
|
80
v3/internal/runtime/desktop/dialogs.js
Normal file
80
v3/internal/runtime/desktop/dialogs.js
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {newRuntimeCaller} from "./runtime";
|
||||
|
||||
import { nanoid } from 'nanoid/non-secure'
|
||||
|
||||
let call = newRuntimeCaller("dialog");
|
||||
|
||||
let dialogResponses = new Map();
|
||||
|
||||
function generateID() {
|
||||
let result;
|
||||
do {
|
||||
result = nanoid();
|
||||
} while (dialogResponses.has(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
export function dialogCallback(id, data, isJSON) {
|
||||
let p = dialogResponses.get(id);
|
||||
if (p) {
|
||||
if (isJSON) {
|
||||
p.resolve(JSON.parse(data));
|
||||
} else {
|
||||
p.resolve(data);
|
||||
}
|
||||
dialogResponses.delete(id);
|
||||
}
|
||||
}
|
||||
export function dialogErrorCallback(id, message) {
|
||||
let p = dialogResponses.get(id);
|
||||
if (p) {
|
||||
p.reject(message);
|
||||
dialogResponses.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
function dialog(type, options) {
|
||||
return new Promise((resolve, reject) => {
|
||||
let id = generateID();
|
||||
options = options || {};
|
||||
options["dialog-id"] = id;
|
||||
dialogResponses.set(id, {resolve, reject});
|
||||
call(type, options).catch((error) => {
|
||||
reject(error);
|
||||
dialogResponses.delete(id);
|
||||
})
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
export function Info(options) {
|
||||
return dialog("Info", options);
|
||||
}
|
||||
|
||||
export function Warning(options) {
|
||||
return dialog("Warning", options);
|
||||
}
|
||||
|
||||
export function Error(options) {
|
||||
return dialog("Error", options);
|
||||
}
|
||||
|
||||
export function Question(options) {
|
||||
return dialog("Question", options);
|
||||
}
|
||||
|
||||
export function OpenFile(options) {
|
||||
return dialog("OpenFile", options);
|
||||
}
|
@ -15,6 +15,8 @@ import {EventsNotify, eventListeners} from "./events";
|
||||
import {SetBindings} from "./bindings";
|
||||
|
||||
|
||||
import {Info, Warning, Error, Question, OpenFile, dialogCallback, dialogErrorCallback, } from "./dialogs";
|
||||
|
||||
import * as Clipboard from './clipboard';
|
||||
import {newWindow} from "./window";
|
||||
|
||||
@ -24,13 +26,14 @@ import {newWindow} from "./window";
|
||||
|
||||
// Internal wails endpoints
|
||||
window.wails = {
|
||||
Callback,
|
||||
callbacks,
|
||||
EventsNotify,
|
||||
eventListeners,
|
||||
SetBindings,
|
||||
...newRuntime(-1),
|
||||
};
|
||||
|
||||
window._wails = {
|
||||
dialogCallback,
|
||||
dialogErrorCallback,
|
||||
}
|
||||
|
||||
|
||||
export function newRuntime(id) {
|
||||
return {
|
||||
@ -41,10 +44,19 @@ export function newRuntime(id) {
|
||||
Clipboard: {
|
||||
...Clipboard
|
||||
},
|
||||
Dialog: {
|
||||
Info,
|
||||
Warning,
|
||||
Error,
|
||||
Question,
|
||||
OpenFile,
|
||||
},
|
||||
Window: newWindow(id),
|
||||
Show: () => invoke("S"),
|
||||
Hide: () => invoke("H"),
|
||||
Quit: () => invoke("Q"),
|
||||
Application: {
|
||||
Show: () => invoke("S"),
|
||||
Hide: () => invoke("H"),
|
||||
Quit: () => invoke("Q"),
|
||||
}
|
||||
// GetWindow: function (windowID) {
|
||||
// if (!windowID) {
|
||||
// return this.Window;
|
||||
@ -54,8 +66,6 @@ export function newRuntime(id) {
|
||||
}
|
||||
}
|
||||
|
||||
window.runtime = newRuntime(-1);
|
||||
|
||||
if (DEBUG) {
|
||||
console.log("Wails v3.0.0 Debug Mode Enabled");
|
||||
}
|
||||
|
@ -15,11 +15,7 @@ const runtimeURL = window.location.origin + "/wails/runtime";
|
||||
function runtimeCall(method, args) {
|
||||
let url = new URL(runtimeURL);
|
||||
url.searchParams.append("method", method);
|
||||
if (args) {
|
||||
for (let key in args) {
|
||||
url.searchParams.append(key, args[key]);
|
||||
}
|
||||
}
|
||||
url.searchParams.append("args", JSON.stringify(args));
|
||||
return new Promise((resolve, reject) => {
|
||||
fetch(url)
|
||||
.then(response => {
|
||||
@ -41,6 +37,7 @@ function runtimeCall(method, args) {
|
||||
export function newRuntimeCaller(object, id) {
|
||||
if (!id || id === -1) {
|
||||
return function (method, args) {
|
||||
args = args || {};
|
||||
return runtimeCall(object + "." + method, args);
|
||||
};
|
||||
}
|
||||
|
37
v3/internal/runtime/package-lock.json
generated
37
v3/internal/runtime/package-lock.json
generated
@ -11,6 +11,7 @@
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
"happy-dom": "^8.1.5",
|
||||
"nanoid": "^4.0.0",
|
||||
"npm-check-updates": "^16.6.3",
|
||||
"vitest": "^0.28.3"
|
||||
}
|
||||
@ -3013,15 +3014,15 @@
|
||||
"dev": true
|
||||
},
|
||||
"node_modules/nanoid": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
|
||||
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
"nanoid": "bin/nanoid.js"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
"node": "^14 || ^16 || >=18"
|
||||
}
|
||||
},
|
||||
"node_modules/negotiator": {
|
||||
@ -3630,6 +3631,18 @@
|
||||
"node": "^10 || ^12 || >=14"
|
||||
}
|
||||
},
|
||||
"node_modules/postcss/node_modules/nanoid": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||
"dev": true,
|
||||
"bin": {
|
||||
"nanoid": "bin/nanoid.cjs"
|
||||
},
|
||||
"engines": {
|
||||
"node": "^10 || ^12 || ^13.7 || ^14 || >=15.0.1"
|
||||
}
|
||||
},
|
||||
"node_modules/pretty-format": {
|
||||
"version": "27.5.1",
|
||||
"resolved": "https://registry.npmjs.org/pretty-format/-/pretty-format-27.5.1.tgz",
|
||||
@ -7157,9 +7170,9 @@
|
||||
"dev": true
|
||||
},
|
||||
"nanoid": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||
"version": "4.0.0",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-4.0.0.tgz",
|
||||
"integrity": "sha512-IgBP8piMxe/gf73RTQx7hmnhwz0aaEXYakvqZyE302IXW3HyVNhdNGC+O2MwMAVhLEnvXlvKtGbtJf6wvHihCg==",
|
||||
"dev": true
|
||||
},
|
||||
"negotiator": {
|
||||
@ -7606,6 +7619,14 @@
|
||||
"nanoid": "^3.3.4",
|
||||
"picocolors": "^1.0.0",
|
||||
"source-map-js": "^1.0.2"
|
||||
},
|
||||
"dependencies": {
|
||||
"nanoid": {
|
||||
"version": "3.3.4",
|
||||
"resolved": "https://registry.npmjs.org/nanoid/-/nanoid-3.3.4.tgz",
|
||||
"integrity": "sha512-MqBkQh/OHTS2egovRtLk45wEyNXwF+cokD+1YPf9u5VfJiRdAiRwB2froX5Co9Rh20xs4siNPm8naNotSD6RBw==",
|
||||
"dev": true
|
||||
}
|
||||
}
|
||||
},
|
||||
"pretty-format": {
|
||||
|
@ -9,6 +9,7 @@
|
||||
"devDependencies": {
|
||||
"esbuild": "^0.17.5",
|
||||
"happy-dom": "^8.1.5",
|
||||
"nanoid": "^4.0.0",
|
||||
"npm-check-updates": "^16.6.3",
|
||||
"vitest": "^0.28.3"
|
||||
}
|
||||
|
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@ -1 +1 @@
|
||||
(()=>{var v=Object.defineProperty;var C=(o,e)=>{for(var t in e)v(o,t,{get:e[t],enumerable:!0})};var u=null;(function(){let o=function(n){let r=window[n.shift()];for(;r&&n.length;)r=r[n.shift()];return r},e=o(["chrome","webview","postMessage"]),t=o(["webkit","messageHandlers","external","postMessage"]);if(!e&&!t){console.error("Unsupported Platform");return}e&&(u=n=>window.chrome.webview.postMessage(n)),t&&(u=n=>window.webkit.messageHandlers.external.postMessage(n))})();function w(o,e){u(e&&e!==-1?"WINDOWID:"+e+":"+o:o)}var s={};function E(){let o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function O(){return Math.random()*9007199254740991}var f;window.crypto?f=E:f=O;function h(o,e,t){t==null&&(t=0);let n=window.wails.window.ID();return new Promise(function(r,i){let l;do l=o+"-"+f();while(s[l]);let a;t>0&&(a=setTimeout(function(){i(Error("Call to "+o+" timed out. Request ID: "+l))},t)),s[l]={timeoutHandle:a,reject:i,resolve:r};try{let m={name:o,args:e,callbackID:l,windowID:n};window.WailsInvoke("C"+JSON.stringify(m))}catch(m){console.error(m)}})}window.ObfuscatedCall=(o,e,t)=>(t==null&&(t=0),new Promise(function(n,r){let i;do i=o+"-"+f();while(s[i]);let l;t>0&&(l=setTimeout(function(){r(Error("Call to method "+o+" timed out. Request ID: "+i))},t)),s[i]={timeoutHandle:l,reject:r,resolve:n};try{let a={id:o,args:e,callbackID:i,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(a))}catch(a){console.error(a)}}));function x(o){let e;try{e=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw runtime.LogDebug(i),new Error(i)}let t=e.callbackid,n=s[t];if(!n){let r=`Callback '${t}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete s[t],e.error?n.reject(e.error):n.resolve(e.result)}var c={};function I(o){let e=o.name;if(c[e]){let t=c[e].slice();for(let n=0;n<c[e].length;n+=1){let r=c[e][n],i=o.data;r.Callback(i)&&t.splice(n,1)}t.length===0?M(e):c[e]=t}}function S(o){let e;try{e=JSON.parse(o)}catch{let n="Invalid JSON passed to Notify: "+o;throw new Error(n)}I(e)}function M(o){delete c[o],window.WailsInvoke("EX"+o)}window.go={};function y(o){try{o=JSON.parse(o)}catch(e){console.error(e)}window.go=window.go||{},Object.keys(o).forEach(e=>{window.go[e]=window.go[e]||{},Object.keys(o[e]).forEach(t=>{window.go[e][t]=window.go[e][t]||{},Object.keys(o[e][t]).forEach(n=>{window.go[e][t][n]=function(){let r=0;function i(){let l=[].slice.call(arguments);return h([e,t,n].join("."),l,r)}return i.setTimeout=function(l){r=l},i.getTimeout=function(){return r},i}()})})})}var p={};C(p,{SetText:()=>D,Text:()=>H});var T=window.location.origin+"/wails/runtime";function b(o,e){let t=new URL(T);if(t.searchParams.append("method",o),e)for(let n in e)t.searchParams.append(n,e[n]);return new Promise((n,r)=>{fetch(t).then(i=>{if(i.ok)return i.headers.get("content-type")&&i.headers.get("content-type").indexOf("application/json")!==-1?i.json():i.text();r(Error(i.statusText))}).then(i=>n(i)).catch(i=>r(i))})}function d(o,e){return!e||e===-1?function(t,n){return b(o+"."+t,n)}:function(t,n){return n=n||{},n.windowID=e,b(o+"."+t,n)}}var g=d("clipboard");function D(o){return g("SetText",{text:o})}function H(){return g("Text")}function k(o){let e=d("window",o);return{Center:()=>e("Center"),SetTitle:t=>e("SetTitle",{title:t}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(t,n)=>e("SetSize",{width:t,height:n}),Size:()=>e("Size"),SetMaxSize:(t,n)=>e("SetMaxSize",{width:t,height:n}),SetMinSize:(t,n)=>e("SetMinSize",{width:t,height:n}),SetAlwaysOnTop:t=>e("SetAlwaysOnTop",{alwaysOnTop:t}),SetPosition:(t,n)=>e("SetPosition",{x:t,y:n}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(t,n,r,i)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={Callback:x,callbacks:s,EventsNotify:S,eventListeners:c,SetBindings:y};function U(o){return{Clipboard:{...p},Window:k(o),Show:()=>w("S"),Hide:()=>w("H"),Quit:()=>w("Q")}}window.runtime=U(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();
|
||||
(()=>{var I=Object.defineProperty;var M=(t,e)=>{for(var n in e)I(t,n,{get:e[n],enumerable:!0})};var c=null;(function(){let t=function(o){let i=window[o.shift()];for(;i&&o.length;)i=i[o.shift()];return i},e=t(["chrome","webview","postMessage"]),n=t(["webkit","messageHandlers","external","postMessage"]);if(!e&&!n){console.error("Unsupported Platform");return}e&&(c=o=>window.chrome.webview.postMessage(o)),n&&(c=o=>window.webkit.messageHandlers.external.postMessage(o))})();function u(t,e){c(e&&e!==-1?"WINDOWID:"+e+":"+t:t)}var m={};function D(){let t=new Uint32Array(1);return window.crypto.getRandomValues(t)[0]}function T(){return Math.random()*9007199254740991}var w;window.crypto?w=D:w=T;window.ObfuscatedCall=(t,e,n)=>(n==null&&(n=0),new Promise(function(o,i){let r;do r=t+"-"+w();while(m[r]);let p;n>0&&(p=setTimeout(function(){i(Error("Call to method "+t+" timed out. Request ID: "+r))},n)),m[r]={timeoutHandle:p,reject:i,resolve:o};try{let f={id:t,args:e,callbackID:r,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(f))}catch(f){console.error(f)}}));window.go={};var W=window.location.origin+"/wails/runtime";function h(t,e){let n=new URL(W);return n.searchParams.append("method",t),n.searchParams.append("args",JSON.stringify(e)),new Promise((o,i)=>{fetch(n).then(r=>{if(r.ok)return r.headers.get("content-type")&&r.headers.get("content-type").indexOf("application/json")!==-1?r.json():r.text();i(Error(r.statusText))}).then(r=>o(r)).catch(r=>i(r))})}function s(t,e){return!e||e===-1?function(n,o){return o=o||{},h(t+"."+n,o)}:function(n,o){return o=o||{},o.windowID=e,h(t+"."+n,o)}}var H="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var x=(t=21)=>{let e="",n=t;for(;n--;)e+=H[Math.random()*64|0];return e};var P=s("dialog"),l=new Map;function U(){let t;do t=x();while(l.has(t));return t}function g(t,e,n){let o=l.get(t);o&&(n?o.resolve(JSON.parse(e)):o.resolve(e),l.delete(t))}function S(t,e){let n=l.get(t);n&&(n.reject(e),l.delete(t))}function a(t,e){return new Promise((n,o)=>{let i=U();e=e||{},e["dialog-id"]=i,l.set(i,{resolve:n,reject:o}),P(t,e).catch(r=>{o(r),l.delete(i)})})}function b(t){return a("Info",t)}function y(t){return a("Warning",t)}function C(t){return a("Error",t)}function k(t){return a("Question",t)}function E(t){return a("OpenFile",t)}var d={};M(d,{SetText:()=>J,Text:()=>L});var O=s("clipboard");function J(t){return O("SetText",{text:t})}function L(){return O("Text")}function v(t){let e=s("window",t);return{Center:()=>e("Center"),SetTitle:n=>e("SetTitle",{title:n}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(n,o)=>e("SetSize",{width:n,height:o}),Size:()=>e("Size"),SetMaxSize:(n,o)=>e("SetMaxSize",{width:n,height:o}),SetMinSize:(n,o)=>e("SetMinSize",{width:n,height:o}),SetAlwaysOnTop:n=>e("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,o)=>e("SetPosition",{x:n,y:o}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(n,o,i,r)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={...z(-1)};window._wails={dialogCallback:g,dialogErrorCallback:S};function z(t){return{Clipboard:{...d},Dialog:{Info:b,Warning:y,Error:C,Question:k,OpenFile:E},Window:v(t),Application:{Show:()=>u("S"),Hide:()=>u("H"),Quit:()=>u("Q")}}}console.log("Wails v3.0.0 Debug Mode Enabled");})();
|
||||
|
@ -1 +1 @@
|
||||
(()=>{var v=Object.defineProperty;var C=(o,e)=>{for(var t in e)v(o,t,{get:e[t],enumerable:!0})};var u=null;(function(){let o=function(n){let r=window[n.shift()];for(;r&&n.length;)r=r[n.shift()];return r},e=o(["chrome","webview","postMessage"]),t=o(["webkit","messageHandlers","external","postMessage"]);if(!e&&!t){console.error("Unsupported Platform");return}e&&(u=n=>window.chrome.webview.postMessage(n)),t&&(u=n=>window.webkit.messageHandlers.external.postMessage(n))})();function w(o,e){u(e&&e!==-1?"WINDOWID:"+e+":"+o:o)}var s={};function E(){let o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function O(){return Math.random()*9007199254740991}var f;window.crypto?f=E:f=O;function h(o,e,t){t==null&&(t=0);let n=window.wails.window.ID();return new Promise(function(r,i){let l;do l=o+"-"+f();while(s[l]);let a;t>0&&(a=setTimeout(function(){i(Error("Call to "+o+" timed out. Request ID: "+l))},t)),s[l]={timeoutHandle:a,reject:i,resolve:r};try{let m={name:o,args:e,callbackID:l,windowID:n};window.WailsInvoke("C"+JSON.stringify(m))}catch(m){console.error(m)}})}window.ObfuscatedCall=(o,e,t)=>(t==null&&(t=0),new Promise(function(n,r){let i;do i=o+"-"+f();while(s[i]);let l;t>0&&(l=setTimeout(function(){r(Error("Call to method "+o+" timed out. Request ID: "+i))},t)),s[i]={timeoutHandle:l,reject:r,resolve:n};try{let a={id:o,args:e,callbackID:i,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(a))}catch(a){console.error(a)}}));function x(o){let e;try{e=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw runtime.LogDebug(i),new Error(i)}let t=e.callbackid,n=s[t];if(!n){let r=`Callback '${t}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete s[t],e.error?n.reject(e.error):n.resolve(e.result)}var c={};function I(o){let e=o.name;if(c[e]){let t=c[e].slice();for(let n=0;n<c[e].length;n+=1){let r=c[e][n],i=o.data;r.Callback(i)&&t.splice(n,1)}t.length===0?M(e):c[e]=t}}function S(o){let e;try{e=JSON.parse(o)}catch{let n="Invalid JSON passed to Notify: "+o;throw new Error(n)}I(e)}function M(o){delete c[o],window.WailsInvoke("EX"+o)}window.go={};function y(o){try{o=JSON.parse(o)}catch(e){console.error(e)}window.go=window.go||{},Object.keys(o).forEach(e=>{window.go[e]=window.go[e]||{},Object.keys(o[e]).forEach(t=>{window.go[e][t]=window.go[e][t]||{},Object.keys(o[e][t]).forEach(n=>{window.go[e][t][n]=function(){let r=0;function i(){let l=[].slice.call(arguments);return h([e,t,n].join("."),l,r)}return i.setTimeout=function(l){r=l},i.getTimeout=function(){return r},i}()})})})}var p={};C(p,{SetText:()=>D,Text:()=>H});var T=window.location.origin+"/wails/runtime";function b(o,e){let t=new URL(T);if(t.searchParams.append("method",o),e)for(let n in e)t.searchParams.append(n,e[n]);return new Promise((n,r)=>{fetch(t).then(i=>{if(i.ok)return i.headers.get("content-type")&&i.headers.get("content-type").indexOf("application/json")!==-1?i.json():i.text();r(Error(i.statusText))}).then(i=>n(i)).catch(i=>r(i))})}function d(o,e){return!e||e===-1?function(t,n){return b(o+"."+t,n)}:function(t,n){return n=n||{},n.windowID=e,b(o+"."+t,n)}}var g=d("clipboard");function D(o){return g("SetText",{text:o})}function H(){return g("Text")}function k(o){let e=d("window",o);return{Center:()=>e("Center"),SetTitle:t=>e("SetTitle",{title:t}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(t,n)=>e("SetSize",{width:t,height:n}),Size:()=>e("Size"),SetMaxSize:(t,n)=>e("SetMaxSize",{width:t,height:n}),SetMinSize:(t,n)=>e("SetMinSize",{width:t,height:n}),SetAlwaysOnTop:t=>e("SetAlwaysOnTop",{alwaysOnTop:t}),SetPosition:(t,n)=>e("SetPosition",{x:t,y:n}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(t,n,r,i)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={Callback:x,callbacks:s,EventsNotify:S,eventListeners:c,SetBindings:y};function U(o){return{Clipboard:{...p},Window:k(o),Show:()=>w("S"),Hide:()=>w("H"),Quit:()=>w("Q")}}window.runtime=U(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();
|
||||
(()=>{var I=Object.defineProperty;var M=(t,e)=>{for(var n in e)I(t,n,{get:e[n],enumerable:!0})};var c=null;(function(){let t=function(o){let i=window[o.shift()];for(;i&&o.length;)i=i[o.shift()];return i},e=t(["chrome","webview","postMessage"]),n=t(["webkit","messageHandlers","external","postMessage"]);if(!e&&!n){console.error("Unsupported Platform");return}e&&(c=o=>window.chrome.webview.postMessage(o)),n&&(c=o=>window.webkit.messageHandlers.external.postMessage(o))})();function u(t,e){c(e&&e!==-1?"WINDOWID:"+e+":"+t:t)}var m={};function D(){let t=new Uint32Array(1);return window.crypto.getRandomValues(t)[0]}function T(){return Math.random()*9007199254740991}var w;window.crypto?w=D:w=T;window.ObfuscatedCall=(t,e,n)=>(n==null&&(n=0),new Promise(function(o,i){let r;do r=t+"-"+w();while(m[r]);let p;n>0&&(p=setTimeout(function(){i(Error("Call to method "+t+" timed out. Request ID: "+r))},n)),m[r]={timeoutHandle:p,reject:i,resolve:o};try{let f={id:t,args:e,callbackID:r,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(f))}catch(f){console.error(f)}}));window.go={};var W=window.location.origin+"/wails/runtime";function h(t,e){let n=new URL(W);return n.searchParams.append("method",t),n.searchParams.append("args",JSON.stringify(e)),new Promise((o,i)=>{fetch(n).then(r=>{if(r.ok)return r.headers.get("content-type")&&r.headers.get("content-type").indexOf("application/json")!==-1?r.json():r.text();i(Error(r.statusText))}).then(r=>o(r)).catch(r=>i(r))})}function s(t,e){return!e||e===-1?function(n,o){return o=o||{},h(t+"."+n,o)}:function(n,o){return o=o||{},o.windowID=e,h(t+"."+n,o)}}var H="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var x=(t=21)=>{let e="",n=t;for(;n--;)e+=H[Math.random()*64|0];return e};var P=s("dialog"),l=new Map;function U(){let t;do t=x();while(l.has(t));return t}function g(t,e,n){let o=l.get(t);o&&(n?o.resolve(JSON.parse(e)):o.resolve(e),l.delete(t))}function S(t,e){let n=l.get(t);n&&(n.reject(e),l.delete(t))}function a(t,e){return new Promise((n,o)=>{let i=U();e=e||{},e["dialog-id"]=i,l.set(i,{resolve:n,reject:o}),P(t,e).catch(r=>{o(r),l.delete(i)})})}function b(t){return a("Info",t)}function y(t){return a("Warning",t)}function C(t){return a("Error",t)}function k(t){return a("Question",t)}function E(t){return a("OpenFile",t)}var d={};M(d,{SetText:()=>J,Text:()=>L});var O=s("clipboard");function J(t){return O("SetText",{text:t})}function L(){return O("Text")}function v(t){let e=s("window",t);return{Center:()=>e("Center"),SetTitle:n=>e("SetTitle",{title:n}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(n,o)=>e("SetSize",{width:n,height:o}),Size:()=>e("Size"),SetMaxSize:(n,o)=>e("SetMaxSize",{width:n,height:o}),SetMinSize:(n,o)=>e("SetMinSize",{width:n,height:o}),SetAlwaysOnTop:n=>e("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,o)=>e("SetPosition",{x:n,y:o}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(n,o,i,r)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={...z(-1)};window._wails={dialogCallback:g,dialogErrorCallback:S};function z(t){return{Clipboard:{...d},Dialog:{Info:b,Warning:y,Error:C,Question:k,OpenFile:E},Window:v(t),Application:{Show:()=>u("S"),Hide:()=>u("H"),Quit:()=>u("Q")}}}console.log("Wails v3.0.0 Debug Mode Enabled");})();
|
||||
|
@ -1 +1 @@
|
||||
(()=>{var v=Object.defineProperty;var C=(o,e)=>{for(var t in e)v(o,t,{get:e[t],enumerable:!0})};var u=null;(function(){let o=function(n){let r=window[n.shift()];for(;r&&n.length;)r=r[n.shift()];return r},e=o(["chrome","webview","postMessage"]),t=o(["webkit","messageHandlers","external","postMessage"]);if(!e&&!t){console.error("Unsupported Platform");return}e&&(u=n=>window.chrome.webview.postMessage(n)),t&&(u=n=>window.webkit.messageHandlers.external.postMessage(n))})();function w(o,e){u(e&&e!==-1?"WINDOWID:"+e+":"+o:o)}var s={};function E(){let o=new Uint32Array(1);return window.crypto.getRandomValues(o)[0]}function O(){return Math.random()*9007199254740991}var f;window.crypto?f=E:f=O;function h(o,e,t){t==null&&(t=0);let n=window.wails.window.ID();return new Promise(function(r,i){let l;do l=o+"-"+f();while(s[l]);let a;t>0&&(a=setTimeout(function(){i(Error("Call to "+o+" timed out. Request ID: "+l))},t)),s[l]={timeoutHandle:a,reject:i,resolve:r};try{let m={name:o,args:e,callbackID:l,windowID:n};window.WailsInvoke("C"+JSON.stringify(m))}catch(m){console.error(m)}})}window.ObfuscatedCall=(o,e,t)=>(t==null&&(t=0),new Promise(function(n,r){let i;do i=o+"-"+f();while(s[i]);let l;t>0&&(l=setTimeout(function(){r(Error("Call to method "+o+" timed out. Request ID: "+i))},t)),s[i]={timeoutHandle:l,reject:r,resolve:n};try{let a={id:o,args:e,callbackID:i,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(a))}catch(a){console.error(a)}}));function x(o){let e;try{e=JSON.parse(o)}catch(r){let i=`Invalid JSON passed to callback: ${r.message}. Message: ${o}`;throw runtime.LogDebug(i),new Error(i)}let t=e.callbackid,n=s[t];if(!n){let r=`Callback '${t}' not registered!!!`;throw console.error(r),new Error(r)}clearTimeout(n.timeoutHandle),delete s[t],e.error?n.reject(e.error):n.resolve(e.result)}var c={};function I(o){let e=o.name;if(c[e]){let t=c[e].slice();for(let n=0;n<c[e].length;n+=1){let r=c[e][n],i=o.data;r.Callback(i)&&t.splice(n,1)}t.length===0?M(e):c[e]=t}}function S(o){let e;try{e=JSON.parse(o)}catch{let n="Invalid JSON passed to Notify: "+o;throw new Error(n)}I(e)}function M(o){delete c[o],window.WailsInvoke("EX"+o)}window.go={};function y(o){try{o=JSON.parse(o)}catch(e){console.error(e)}window.go=window.go||{},Object.keys(o).forEach(e=>{window.go[e]=window.go[e]||{},Object.keys(o[e]).forEach(t=>{window.go[e][t]=window.go[e][t]||{},Object.keys(o[e][t]).forEach(n=>{window.go[e][t][n]=function(){let r=0;function i(){let l=[].slice.call(arguments);return h([e,t,n].join("."),l,r)}return i.setTimeout=function(l){r=l},i.getTimeout=function(){return r},i}()})})})}var p={};C(p,{SetText:()=>D,Text:()=>H});var T=window.location.origin+"/wails/runtime";function b(o,e){let t=new URL(T);if(t.searchParams.append("method",o),e)for(let n in e)t.searchParams.append(n,e[n]);return new Promise((n,r)=>{fetch(t).then(i=>{if(i.ok)return i.headers.get("content-type")&&i.headers.get("content-type").indexOf("application/json")!==-1?i.json():i.text();r(Error(i.statusText))}).then(i=>n(i)).catch(i=>r(i))})}function d(o,e){return!e||e===-1?function(t,n){return b(o+"."+t,n)}:function(t,n){return n=n||{},n.windowID=e,b(o+"."+t,n)}}var g=d("clipboard");function D(o){return g("SetText",{text:o})}function H(){return g("Text")}function k(o){let e=d("window",o);return{Center:()=>e("Center"),SetTitle:t=>e("SetTitle",{title:t}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(t,n)=>e("SetSize",{width:t,height:n}),Size:()=>e("Size"),SetMaxSize:(t,n)=>e("SetMaxSize",{width:t,height:n}),SetMinSize:(t,n)=>e("SetMinSize",{width:t,height:n}),SetAlwaysOnTop:t=>e("SetAlwaysOnTop",{alwaysOnTop:t}),SetPosition:(t,n)=>e("SetPosition",{x:t,y:n}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(t,n,r,i)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={Callback:x,callbacks:s,EventsNotify:S,eventListeners:c,SetBindings:y};function U(o){return{Clipboard:{...p},Window:k(o),Show:()=>w("S"),Hide:()=>w("H"),Quit:()=>w("Q")}}window.runtime=U(-1);console.log("Wails v3.0.0 Debug Mode Enabled");})();
|
||||
(()=>{var I=Object.defineProperty;var M=(t,e)=>{for(var n in e)I(t,n,{get:e[n],enumerable:!0})};var c=null;(function(){let t=function(o){let i=window[o.shift()];for(;i&&o.length;)i=i[o.shift()];return i},e=t(["chrome","webview","postMessage"]),n=t(["webkit","messageHandlers","external","postMessage"]);if(!e&&!n){console.error("Unsupported Platform");return}e&&(c=o=>window.chrome.webview.postMessage(o)),n&&(c=o=>window.webkit.messageHandlers.external.postMessage(o))})();function u(t,e){c(e&&e!==-1?"WINDOWID:"+e+":"+t:t)}var m={};function D(){let t=new Uint32Array(1);return window.crypto.getRandomValues(t)[0]}function T(){return Math.random()*9007199254740991}var w;window.crypto?w=D:w=T;window.ObfuscatedCall=(t,e,n)=>(n==null&&(n=0),new Promise(function(o,i){let r;do r=t+"-"+w();while(m[r]);let p;n>0&&(p=setTimeout(function(){i(Error("Call to method "+t+" timed out. Request ID: "+r))},n)),m[r]={timeoutHandle:p,reject:i,resolve:o};try{let f={id:t,args:e,callbackID:r,windowID:window.wails.window.ID()};window.WailsInvoke("c"+JSON.stringify(f))}catch(f){console.error(f)}}));window.go={};var W=window.location.origin+"/wails/runtime";function h(t,e){let n=new URL(W);return n.searchParams.append("method",t),n.searchParams.append("args",JSON.stringify(e)),new Promise((o,i)=>{fetch(n).then(r=>{if(r.ok)return r.headers.get("content-type")&&r.headers.get("content-type").indexOf("application/json")!==-1?r.json():r.text();i(Error(r.statusText))}).then(r=>o(r)).catch(r=>i(r))})}function s(t,e){return!e||e===-1?function(n,o){return o=o||{},h(t+"."+n,o)}:function(n,o){return o=o||{},o.windowID=e,h(t+"."+n,o)}}var H="useandom-26T198340PX75pxJACKVERYMINDBUSHWOLF_GQZbfghjklqvwyzrict";var x=(t=21)=>{let e="",n=t;for(;n--;)e+=H[Math.random()*64|0];return e};var P=s("dialog"),l=new Map;function U(){let t;do t=x();while(l.has(t));return t}function g(t,e,n){let o=l.get(t);o&&(n?o.resolve(JSON.parse(e)):o.resolve(e),l.delete(t))}function S(t,e){let n=l.get(t);n&&(n.reject(e),l.delete(t))}function a(t,e){return new Promise((n,o)=>{let i=U();e=e||{},e["dialog-id"]=i,l.set(i,{resolve:n,reject:o}),P(t,e).catch(r=>{o(r),l.delete(i)})})}function b(t){return a("Info",t)}function y(t){return a("Warning",t)}function C(t){return a("Error",t)}function k(t){return a("Question",t)}function E(t){return a("OpenFile",t)}var d={};M(d,{SetText:()=>J,Text:()=>L});var O=s("clipboard");function J(t){return O("SetText",{text:t})}function L(){return O("Text")}function v(t){let e=s("window",t);return{Center:()=>e("Center"),SetTitle:n=>e("SetTitle",{title:n}),Fullscreen:()=>e("Fullscreen"),UnFullscreen:()=>e("UnFullscreen"),SetSize:(n,o)=>e("SetSize",{width:n,height:o}),Size:()=>e("Size"),SetMaxSize:(n,o)=>e("SetMaxSize",{width:n,height:o}),SetMinSize:(n,o)=>e("SetMinSize",{width:n,height:o}),SetAlwaysOnTop:n=>e("SetAlwaysOnTop",{alwaysOnTop:n}),SetPosition:(n,o)=>e("SetPosition",{x:n,y:o}),Position:()=>e("Position"),Screen:()=>e("Screen"),Hide:()=>e("Hide"),Maximise:()=>e("Maximise"),Show:()=>e("Show"),ToggleMaximise:()=>e("ToggleMaximise"),UnMaximise:()=>e("UnMaximise"),Minimise:()=>e("Minimise"),UnMinimise:()=>e("UnMinimise"),SetBackgroundColour:(n,o,i,r)=>e("SetBackgroundColour",{R,G,B,A})}}window.wails={...z(-1)};window._wails={dialogCallback:g,dialogErrorCallback:S};function z(t){return{Clipboard:{...d},Dialog:{Info:b,Warning:y,Error:C,Question:k,OpenFile:E},Window:v(t),Application:{Show:()=>u("S"),Hide:()=>u("H"),Quit:()=>u("Q")}}}console.log("Wails v3.0.0 Debug Mode Enabled");})();
|
||||
|
@ -228,7 +228,7 @@ func (a *App) Run() error {
|
||||
// set the application menu
|
||||
a.impl.setApplicationMenu(a.ApplicationMenu)
|
||||
|
||||
// set the application icon
|
||||
// set the application Icon
|
||||
a.impl.setIcon(a.options.Icon)
|
||||
|
||||
return a.impl.run()
|
||||
@ -389,3 +389,9 @@ func (a *App) dispatchOnMainThread(fn func()) {
|
||||
// Call platform specific dispatch function
|
||||
a.impl.dispatchOnMainThread(id)
|
||||
}
|
||||
|
||||
func (a *App) OpenFileDialogWithOptions(options *OpenFileDialogOptions) *OpenFileDialog {
|
||||
result := a.OpenFileDialog()
|
||||
result.SetOptions(options)
|
||||
return result
|
||||
}
|
||||
|
@ -46,9 +46,9 @@ const (
|
||||
)
|
||||
|
||||
type Button struct {
|
||||
label string
|
||||
isCancel bool
|
||||
isDefault bool
|
||||
Label string
|
||||
IsCancel bool
|
||||
IsDefault bool
|
||||
callback func()
|
||||
}
|
||||
|
||||
@ -60,12 +60,16 @@ type messageDialogImpl interface {
|
||||
show()
|
||||
}
|
||||
|
||||
type MessageDialogOptions struct {
|
||||
DialogType DialogType
|
||||
Title string
|
||||
Message string
|
||||
Buttons []*Button
|
||||
Icon []byte
|
||||
}
|
||||
|
||||
type MessageDialog struct {
|
||||
dialogType DialogType
|
||||
title string
|
||||
message string
|
||||
buttons []*Button
|
||||
icon []byte
|
||||
MessageDialogOptions
|
||||
|
||||
// platform independent
|
||||
impl messageDialogImpl
|
||||
@ -80,13 +84,16 @@ var defaultTitles = map[DialogType]string{
|
||||
|
||||
func newMessageDialog(dialogType DialogType) *MessageDialog {
|
||||
return &MessageDialog{
|
||||
dialogType: dialogType,
|
||||
title: defaultTitles[dialogType],
|
||||
MessageDialogOptions: MessageDialogOptions{
|
||||
DialogType: dialogType,
|
||||
Title: defaultTitles[dialogType],
|
||||
},
|
||||
impl: nil,
|
||||
}
|
||||
}
|
||||
|
||||
func (d *MessageDialog) SetTitle(title string) *MessageDialog {
|
||||
d.title = title
|
||||
d.Title = title
|
||||
return d
|
||||
}
|
||||
|
||||
@ -98,36 +105,41 @@ func (d *MessageDialog) Show() {
|
||||
}
|
||||
|
||||
func (d *MessageDialog) SetIcon(icon []byte) *MessageDialog {
|
||||
d.icon = icon
|
||||
d.Icon = icon
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *MessageDialog) AddButton(s string) *Button {
|
||||
result := &Button{
|
||||
label: s,
|
||||
Label: s,
|
||||
}
|
||||
d.buttons = append(d.buttons, result)
|
||||
d.Buttons = append(d.Buttons, result)
|
||||
return result
|
||||
}
|
||||
|
||||
func (d *MessageDialog) AddButtons(buttons []*Button) *MessageDialog {
|
||||
d.Buttons = buttons
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *MessageDialog) SetDefaultButton(button *Button) *MessageDialog {
|
||||
for _, b := range d.buttons {
|
||||
b.isDefault = false
|
||||
for _, b := range d.Buttons {
|
||||
b.IsDefault = false
|
||||
}
|
||||
button.isDefault = true
|
||||
button.IsDefault = true
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *MessageDialog) SetCancelButton(button *Button) *MessageDialog {
|
||||
for _, b := range d.buttons {
|
||||
b.isCancel = false
|
||||
for _, b := range d.Buttons {
|
||||
b.IsCancel = false
|
||||
}
|
||||
button.isCancel = true
|
||||
button.IsCancel = true
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *MessageDialog) SetMessage(title string) *MessageDialog {
|
||||
d.title = title
|
||||
func (d *MessageDialog) SetMessage(message string) *MessageDialog {
|
||||
d.Message = message
|
||||
return d
|
||||
}
|
||||
|
||||
@ -135,9 +147,28 @@ type openFileDialogImpl interface {
|
||||
show() ([]string, error)
|
||||
}
|
||||
|
||||
type fileFilter struct {
|
||||
displayName string // Filter information EG: "Image Files (*.jpg, *.png)"
|
||||
pattern string // semicolon separated list of extensions, EG: "*.jpg;*.png"
|
||||
type FileFilter struct {
|
||||
DisplayName string // Filter information EG: "Image Files (*.jpg, *.png)"
|
||||
Pattern string // semicolon separated list of extensions, EG: "*.jpg;*.png"
|
||||
}
|
||||
|
||||
type OpenFileDialogOptions struct {
|
||||
CanChooseDirectories bool
|
||||
CanChooseFiles bool
|
||||
CanCreateDirectories bool
|
||||
ShowHiddenFiles bool
|
||||
ResolvesAliases bool
|
||||
AllowsMultipleSelection bool
|
||||
HideExtension bool
|
||||
CanSelectHiddenExtension bool
|
||||
TreatsFilePackagesAsDirectories bool
|
||||
AllowsOtherFileTypes bool
|
||||
Filters []FileFilter
|
||||
|
||||
Title string
|
||||
Message string
|
||||
ButtonText string
|
||||
Directory string
|
||||
}
|
||||
|
||||
type OpenFileDialog struct {
|
||||
@ -152,7 +183,7 @@ type OpenFileDialog struct {
|
||||
canSelectHiddenExtension bool
|
||||
treatsFilePackagesAsDirectories bool
|
||||
allowsOtherFileTypes bool
|
||||
filters []fileFilter
|
||||
filters []FileFilter
|
||||
|
||||
title string
|
||||
message string
|
||||
@ -230,9 +261,9 @@ func (d *OpenFileDialog) PromptForSingleSelection() (string, error) {
|
||||
// AddFilter adds a filter to the dialog. The filter is a display name and a semicolon separated list of extensions.
|
||||
// EG: AddFilter("Image Files", "*.jpg;*.png")
|
||||
func (d *OpenFileDialog) AddFilter(displayName, pattern string) *OpenFileDialog {
|
||||
d.filters = append(d.filters, fileFilter{
|
||||
displayName: strings.TrimSpace(displayName),
|
||||
pattern: strings.TrimSpace(pattern),
|
||||
d.filters = append(d.filters, FileFilter{
|
||||
DisplayName: strings.TrimSpace(displayName),
|
||||
Pattern: strings.TrimSpace(pattern),
|
||||
})
|
||||
return d
|
||||
}
|
||||
@ -265,6 +296,24 @@ func (d *OpenFileDialog) CanSelectHiddenExtension(canSelectHiddenExtension bool)
|
||||
return d
|
||||
}
|
||||
|
||||
func (d *OpenFileDialog) SetOptions(options *OpenFileDialogOptions) {
|
||||
d.title = options.Title
|
||||
d.message = options.Message
|
||||
d.buttonText = options.ButtonText
|
||||
d.directory = options.Directory
|
||||
d.canChooseDirectories = options.CanChooseDirectories
|
||||
d.canChooseFiles = options.CanChooseFiles
|
||||
d.canCreateDirectories = options.CanCreateDirectories
|
||||
d.showHiddenFiles = options.ShowHiddenFiles
|
||||
d.resolvesAliases = options.ResolvesAliases
|
||||
d.allowsMultipleSelection = options.AllowsMultipleSelection
|
||||
d.hideExtension = options.HideExtension
|
||||
d.canSelectHiddenExtension = options.CanSelectHiddenExtension
|
||||
d.treatsFilePackagesAsDirectories = options.TreatsFilePackagesAsDirectories
|
||||
d.allowsOtherFileTypes = options.AllowsOtherFileTypes
|
||||
d.filters = options.Filters
|
||||
}
|
||||
|
||||
func newOpenFileDialog() *OpenFileDialog {
|
||||
return &OpenFileDialog{
|
||||
id: getDialogID(),
|
||||
|
@ -61,7 +61,7 @@ static void* createAlert(int alertType, char* title, char *message, void *icon,
|
||||
NSImage *image = [NSImage imageNamed:NSImageNameInfo];
|
||||
[alert setIcon:image];
|
||||
}
|
||||
}
|
||||
}
|
||||
return alert;
|
||||
|
||||
}
|
||||
@ -315,54 +315,54 @@ type macosDialog struct {
|
||||
func (m *macosDialog) show() {
|
||||
globalApplication.dispatchOnMainThread(func() {
|
||||
|
||||
// Mac can only have 4 buttons on a dialog
|
||||
if len(m.dialog.buttons) > 4 {
|
||||
m.dialog.buttons = m.dialog.buttons[:4]
|
||||
// Mac can only have 4 Buttons on a dialog
|
||||
if len(m.dialog.Buttons) > 4 {
|
||||
m.dialog.Buttons = m.dialog.Buttons[:4]
|
||||
}
|
||||
|
||||
if m.nsDialog != nil {
|
||||
C.releaseDialog(m.nsDialog)
|
||||
}
|
||||
var title *C.char
|
||||
if m.dialog.title != "" {
|
||||
title = C.CString(m.dialog.title)
|
||||
if m.dialog.Title != "" {
|
||||
title = C.CString(m.dialog.Title)
|
||||
}
|
||||
var message *C.char
|
||||
if m.dialog.message != "" {
|
||||
message = C.CString(m.dialog.message)
|
||||
if m.dialog.Message != "" {
|
||||
message = C.CString(m.dialog.Message)
|
||||
}
|
||||
var iconData unsafe.Pointer
|
||||
var iconLength C.int
|
||||
if m.dialog.icon != nil {
|
||||
iconData = unsafe.Pointer(&m.dialog.icon[0])
|
||||
iconLength = C.int(len(m.dialog.icon))
|
||||
if m.dialog.Icon != nil {
|
||||
iconData = unsafe.Pointer(&m.dialog.Icon[0])
|
||||
iconLength = C.int(len(m.dialog.Icon))
|
||||
} else {
|
||||
// if it's an error, use the application icon
|
||||
if m.dialog.dialogType == ErrorDialog {
|
||||
// if it's an error, use the application Icon
|
||||
if m.dialog.DialogType == ErrorDialog {
|
||||
iconData = unsafe.Pointer(&globalApplication.options.Icon[0])
|
||||
iconLength = C.int(len(globalApplication.options.Icon))
|
||||
}
|
||||
}
|
||||
|
||||
alertType, ok := alertTypeMap[m.dialog.dialogType]
|
||||
alertType, ok := alertTypeMap[m.dialog.DialogType]
|
||||
if !ok {
|
||||
alertType = C.NSAlertStyleInformational
|
||||
}
|
||||
|
||||
m.nsDialog = C.createAlert(alertType, title, message, iconData, iconLength)
|
||||
|
||||
// Reverse the buttons so that the default is on the right
|
||||
reversedButtons := make([]*Button, len(m.dialog.buttons))
|
||||
// Reverse the Buttons so that the default is on the right
|
||||
reversedButtons := make([]*Button, len(m.dialog.Buttons))
|
||||
var count = 0
|
||||
for i := len(m.dialog.buttons) - 1; i >= 0; i-- {
|
||||
button := m.dialog.buttons[i]
|
||||
C.alertAddButton(m.nsDialog, C.CString(button.label), C.bool(button.isDefault), C.bool(button.isCancel))
|
||||
reversedButtons[count] = m.dialog.buttons[i]
|
||||
for i := len(m.dialog.Buttons) - 1; i >= 0; i-- {
|
||||
button := m.dialog.Buttons[i]
|
||||
C.alertAddButton(m.nsDialog, C.CString(button.Label), C.bool(button.IsDefault), C.bool(button.IsCancel))
|
||||
reversedButtons[count] = m.dialog.Buttons[i]
|
||||
count++
|
||||
}
|
||||
|
||||
buttonPressed := int(C.dialogRunModal(m.nsDialog))
|
||||
if len(m.dialog.buttons) > buttonPressed {
|
||||
if len(m.dialog.Buttons) > buttonPressed {
|
||||
button := reversedButtons[buttonPressed]
|
||||
if button.callback != nil {
|
||||
button.callback()
|
||||
@ -410,7 +410,7 @@ func (m *macosOpenFileDialog) show() ([]string, error) {
|
||||
if len(m.dialog.filters) > 0 {
|
||||
var allPatterns []string
|
||||
for _, filter := range m.dialog.filters {
|
||||
patternComponents := strings.Split(filter.pattern, ";")
|
||||
patternComponents := strings.Split(filter.Pattern, ";")
|
||||
for i, component := range patternComponents {
|
||||
filterPattern := strings.TrimSpace(component)
|
||||
filterPattern = strings.TrimPrefix(filterPattern, "*.")
|
||||
|
@ -21,7 +21,7 @@ func NewMessageProcessor(w *WebviewWindow) *MessageProcessor {
|
||||
func (m *MessageProcessor) httpError(rw http.ResponseWriter, message string, args ...any) {
|
||||
m.Error(message, args...)
|
||||
rw.WriteHeader(http.StatusBadRequest)
|
||||
rw.Write([]byte(message))
|
||||
rw.Write([]byte(fmt.Sprintf(message, args...)))
|
||||
}
|
||||
|
||||
func (m *MessageProcessor) HandleRuntimeCall(rw http.ResponseWriter, r *http.Request) {
|
||||
@ -59,6 +59,8 @@ func (m *MessageProcessor) HandleRuntimeCall(rw http.ResponseWriter, r *http.Req
|
||||
m.processWindowMethod(method, rw, r, targetWindow, params)
|
||||
case "clipboard":
|
||||
m.processClipboardMethod(method, rw, r, targetWindow, params)
|
||||
case "dialog":
|
||||
m.processDialogMethod(method, rw, r, targetWindow, params)
|
||||
default:
|
||||
m.httpError(rw, "Unknown runtime call: %s", object)
|
||||
}
|
||||
|
@ -4,11 +4,11 @@ import (
|
||||
"net/http"
|
||||
)
|
||||
|
||||
func (m *MessageProcessor) processClipboardMethod(method string, rw http.ResponseWriter, r *http.Request, window *WebviewWindow, params QueryParams) {
|
||||
func (m *MessageProcessor) processClipboardMethod(method string, rw http.ResponseWriter, r *http.Request, window *WebviewWindow, args QueryParams) {
|
||||
|
||||
switch method {
|
||||
case "SetText":
|
||||
title := params.String("text")
|
||||
title := args.String("text")
|
||||
if title == nil {
|
||||
m.Error("SetText: text is required")
|
||||
return
|
||||
|
109
v3/pkg/application/messageprocessor_dialog.go
Normal file
109
v3/pkg/application/messageprocessor_dialog.go
Normal file
@ -0,0 +1,109 @@
|
||||
package application
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"net/http"
|
||||
"runtime"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
func (m *MessageProcessor) dialogErrorCallback(message string, dialogID *string, err error) {
|
||||
errorMsg := fmt.Sprintf(message, err)
|
||||
m.Error(errorMsg)
|
||||
msg := "_wails.dialogErrorCallback('" + *dialogID + "', " + strconv.Quote(errorMsg) + ");"
|
||||
m.window.ExecJS(msg)
|
||||
}
|
||||
|
||||
func (m *MessageProcessor) dialogCallback(dialogID *string, result string, isJSON bool) {
|
||||
msg := fmt.Sprintf("_wails.dialogCallback('%s', %s, %v);", *dialogID, strconv.Quote(result), isJSON)
|
||||
m.window.ExecJS(msg)
|
||||
}
|
||||
|
||||
func (m *MessageProcessor) processDialogMethod(method string, rw http.ResponseWriter, r *http.Request, window *WebviewWindow, params QueryParams) {
|
||||
|
||||
args, err := params.Args()
|
||||
if err != nil {
|
||||
m.httpError(rw, "Unable to parse arguments: %s", err)
|
||||
return
|
||||
}
|
||||
dialogID := args.String("dialog-id")
|
||||
if dialogID == nil {
|
||||
m.Error("dialog-id is required")
|
||||
return
|
||||
}
|
||||
switch method {
|
||||
case "Info", "Warning", "Error", "Question":
|
||||
var options MessageDialogOptions
|
||||
err := params.ToStruct(&options)
|
||||
if err != nil {
|
||||
m.dialogErrorCallback("Error parsing dialog options: %s", dialogID, err)
|
||||
return
|
||||
}
|
||||
if len(options.Buttons) == 0 {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
options.Buttons = []*Button{{Label: "OK", IsDefault: true}}
|
||||
}
|
||||
}
|
||||
var dialog *MessageDialog
|
||||
switch method {
|
||||
case "Info":
|
||||
dialog = globalApplication.InfoDialog()
|
||||
case "Warning":
|
||||
dialog = globalApplication.WarningDialog()
|
||||
case "Error":
|
||||
dialog = globalApplication.ErrorDialog()
|
||||
case "Question":
|
||||
dialog = globalApplication.QuestionDialog()
|
||||
}
|
||||
// TODO: Add support for attaching Message dialogs to windows
|
||||
dialog.SetTitle(options.Title)
|
||||
dialog.SetMessage(options.Message)
|
||||
for _, button := range options.Buttons {
|
||||
label := button.Label
|
||||
button.OnClick(func() {
|
||||
m.dialogCallback(dialogID, label, false)
|
||||
})
|
||||
}
|
||||
dialog.AddButtons(options.Buttons)
|
||||
dialog.Show()
|
||||
m.ok(rw)
|
||||
case "OpenFile":
|
||||
var options OpenFileDialogOptions
|
||||
err := params.ToStruct(&options)
|
||||
if err != nil {
|
||||
m.httpError(rw, "Error parsing dialog options: %s", err.Error())
|
||||
return
|
||||
}
|
||||
dialog := globalApplication.OpenFileDialogWithOptions(&options)
|
||||
|
||||
go func() {
|
||||
if options.AllowsMultipleSelection {
|
||||
files, err := dialog.PromptForMultipleSelection()
|
||||
if err != nil {
|
||||
m.dialogErrorCallback("Error getting selection: %s", dialogID, err)
|
||||
return
|
||||
} else {
|
||||
result, err := json.Marshal(files)
|
||||
if err != nil {
|
||||
m.dialogErrorCallback("Error marshalling files: %s", dialogID, err)
|
||||
return
|
||||
}
|
||||
m.dialogCallback(dialogID, string(result), true)
|
||||
}
|
||||
} else {
|
||||
file, err := dialog.PromptForSingleSelection()
|
||||
if err != nil {
|
||||
m.dialogErrorCallback("Error getting selection: %s", dialogID, err)
|
||||
return
|
||||
}
|
||||
m.dialogCallback(dialogID, file, false)
|
||||
}
|
||||
}()
|
||||
m.ok(rw)
|
||||
default:
|
||||
m.httpError(rw, "Unknown dialog method: %s", method)
|
||||
}
|
||||
|
||||
}
|
@ -1,6 +1,10 @@
|
||||
package application
|
||||
|
||||
import "strconv"
|
||||
import (
|
||||
"encoding/json"
|
||||
"fmt"
|
||||
"strconv"
|
||||
)
|
||||
|
||||
type QueryParams map[string][]string
|
||||
|
||||
@ -93,3 +97,94 @@ func (qp QueryParams) Float64(key string) *float64 {
|
||||
}
|
||||
return &result
|
||||
}
|
||||
|
||||
func (qp QueryParams) ToStruct(str any) error {
|
||||
args := qp["args"]
|
||||
if len(args) == 1 {
|
||||
return json.Unmarshal([]byte(args[0]), &str)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
type Args struct {
|
||||
data map[string]any
|
||||
}
|
||||
|
||||
func (a *Args) String(key string) *string {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
if val := a.data[key]; val != nil {
|
||||
result := fmt.Sprintf("%v", val)
|
||||
return &result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Args) Int(s string) *int {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
if val := a.data[s]; val != nil {
|
||||
result := val.(int)
|
||||
return &result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Args) UInt8(s string) *uint8 {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
if val := a.data[s]; val != nil {
|
||||
result := val.(uint8)
|
||||
return &result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
func (a *Args) UInt(s string) *uint {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
if val := a.data[s]; val != nil {
|
||||
result := val.(uint)
|
||||
return &result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Args) Float64(s string) *float64 {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
if val := a.data[s]; val != nil {
|
||||
result := val.(float64)
|
||||
return &result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (a *Args) Bool(s string) *bool {
|
||||
if a == nil {
|
||||
return nil
|
||||
}
|
||||
if val := a.data[s]; val != nil {
|
||||
result := val.(bool)
|
||||
return &result
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (qp QueryParams) Args() (*Args, error) {
|
||||
argData := qp["args"]
|
||||
var result = &Args{
|
||||
data: make(map[string]any),
|
||||
}
|
||||
if len(argData) == 1 {
|
||||
err := json.Unmarshal([]byte(argData[0]), &result.data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
@ -8,9 +8,15 @@ import (
|
||||
|
||||
func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWriter, r *http.Request, window *WebviewWindow, params QueryParams) {
|
||||
|
||||
args, err := params.Args()
|
||||
if err != nil {
|
||||
m.httpError(rw, "Unable to parse arguments: %s", err)
|
||||
return
|
||||
}
|
||||
|
||||
switch method {
|
||||
case "SetTitle":
|
||||
title := params.String("title")
|
||||
title := args.String("title")
|
||||
if title == nil {
|
||||
m.Error("SetTitle: title is required")
|
||||
return
|
||||
@ -18,19 +24,19 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
|
||||
window.SetTitle(*title)
|
||||
m.ok(rw)
|
||||
case "SetSize":
|
||||
width := params.Int("width")
|
||||
height := params.Int("height")
|
||||
width := args.Int("width")
|
||||
height := args.Int("height")
|
||||
if width == nil || height == nil {
|
||||
m.Error("Invalid SetSize message")
|
||||
m.Error("Invalid SetSize Message")
|
||||
return
|
||||
}
|
||||
window.SetSize(*width, *height)
|
||||
m.ok(rw)
|
||||
case "SetPosition":
|
||||
x := params.Int("x")
|
||||
y := params.Int("y")
|
||||
x := args.Int("x")
|
||||
y := args.Int("y")
|
||||
if x == nil || y == nil {
|
||||
m.Error("Invalid SetPosition message")
|
||||
m.Error("Invalid SetPosition Message")
|
||||
return
|
||||
}
|
||||
window.SetPosition(*x, *y)
|
||||
@ -78,24 +84,24 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
|
||||
"y": y,
|
||||
})
|
||||
case "SetBackgroundColour":
|
||||
r := params.UInt8("r")
|
||||
r := args.UInt8("r")
|
||||
if r == nil {
|
||||
m.Error("Invalid SetBackgroundColour message: 'r' value required")
|
||||
m.Error("Invalid SetBackgroundColour Message: 'r' value required")
|
||||
return
|
||||
}
|
||||
g := params.UInt8("g")
|
||||
g := args.UInt8("g")
|
||||
if g == nil {
|
||||
m.Error("Invalid SetBackgroundColour message: 'g' value required")
|
||||
m.Error("Invalid SetBackgroundColour Message: 'g' value required")
|
||||
return
|
||||
}
|
||||
b := params.UInt8("b")
|
||||
b := args.UInt8("b")
|
||||
if b == nil {
|
||||
m.Error("Invalid SetBackgroundColour message: 'b' value required")
|
||||
m.Error("Invalid SetBackgroundColour Message: 'b' value required")
|
||||
return
|
||||
}
|
||||
a := params.UInt8("a")
|
||||
a := args.UInt8("a")
|
||||
if a == nil {
|
||||
m.Error("Invalid SetBackgroundColour message: 'a' value required")
|
||||
m.Error("Invalid SetBackgroundColour Message: 'a' value required")
|
||||
return
|
||||
}
|
||||
window.SetBackgroundColour(&options.RGBA{
|
||||
@ -106,35 +112,35 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
|
||||
})
|
||||
m.ok(rw)
|
||||
case "SetAlwaysOnTop":
|
||||
alwaysOnTop := params.Bool("alwaysOnTop")
|
||||
alwaysOnTop := args.Bool("alwaysOnTop")
|
||||
if alwaysOnTop == nil {
|
||||
m.Error("Invalid SetAlwaysOnTop message: 'alwaysOnTop' value required")
|
||||
m.Error("Invalid SetAlwaysOnTop Message: 'alwaysOnTop' value required")
|
||||
return
|
||||
}
|
||||
window.SetAlwaysOnTop(*alwaysOnTop)
|
||||
m.ok(rw)
|
||||
case "SetResizable":
|
||||
resizable := params.Bool("resizable")
|
||||
resizable := args.Bool("resizable")
|
||||
if resizable == nil {
|
||||
m.Error("Invalid SetResizable message: 'resizable' value required")
|
||||
m.Error("Invalid SetResizable Message: 'resizable' value required")
|
||||
return
|
||||
}
|
||||
window.SetResizable(*resizable)
|
||||
m.ok(rw)
|
||||
case "SetMinSize":
|
||||
width := params.Int("width")
|
||||
height := params.Int("height")
|
||||
width := args.Int("width")
|
||||
height := args.Int("height")
|
||||
if width == nil || height == nil {
|
||||
m.Error("Invalid SetMinSize message")
|
||||
m.Error("Invalid SetMinSize Message")
|
||||
return
|
||||
}
|
||||
window.SetMinSize(*width, *height)
|
||||
m.ok(rw)
|
||||
case "SetMaxSize":
|
||||
width := params.Int("width")
|
||||
height := params.Int("height")
|
||||
width := args.Int("width")
|
||||
height := args.Int("height")
|
||||
if width == nil || height == nil {
|
||||
m.Error("Invalid SetMaxSize message")
|
||||
m.Error("Invalid SetMaxSize Message")
|
||||
return
|
||||
}
|
||||
window.SetMaxSize(*width, *height)
|
||||
@ -171,9 +177,9 @@ func (m *MessageProcessor) processWindowMethod(method string, rw http.ResponseWr
|
||||
}
|
||||
m.json(rw, screen)
|
||||
case "SetZoom":
|
||||
zoomLevel := params.Float64("zoomLevel")
|
||||
zoomLevel := args.Float64("zoomLevel")
|
||||
if zoomLevel == nil {
|
||||
m.Error("Invalid SetZoom message: invalid 'zoomLevel' value")
|
||||
m.Error("Invalid SetZoom Message: invalid 'zoomLevel' value")
|
||||
return
|
||||
}
|
||||
window.SetZoom(*zoomLevel)
|
||||
|
Loading…
Reference in New Issue
Block a user