mirror of
https://github.com/wavetermdev/wails.git
synced 2026-08-05 13:53:43 -07:00
Radical JS runtime overhaul. New @wailsio/runtime package
This commit is contained in:
@@ -1,3 +1,3 @@
|
||||
# Runtime
|
||||
|
||||
To rebuild the runtime run `task build-runtime` or if you have Wails v3 CLI, you can use `wails task build-runtime`.
|
||||
To rebuild the runtime run `task build-runtime` or if you have Wails v3 CLI, you can use `wails3 task build-runtime`.
|
||||
|
||||
@@ -21,82 +21,18 @@ tasks:
|
||||
build:debug:
|
||||
internal: true
|
||||
cmds:
|
||||
- npx esbuild desktop/main.js --bundle --tree-shaking=true --sourcemap=inline --outfile=runtime_debug_desktop_{{.PLATFORM}}.js --define:DEBUG=true --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}} --define:INVOKE={{.INVOKE}}
|
||||
|
||||
build:debug:windows:
|
||||
cmds:
|
||||
- task: build:debug
|
||||
vars:
|
||||
WINDOWS: true
|
||||
DARWIN: false
|
||||
LINUX: false
|
||||
PLATFORM: windows
|
||||
INVOKE: "chrome.webview.postMessage"
|
||||
|
||||
build:debug:linux:
|
||||
cmds:
|
||||
- task: build:debug
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: false
|
||||
LINUX: true
|
||||
PLATFORM: linux
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
|
||||
build:debug:darwin:
|
||||
cmds:
|
||||
- task: build:debug
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: true
|
||||
LINUX: false
|
||||
PLATFORM: darwin
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
- npx esbuild@latest desktop/main.js --bundle --tree-shaking=true --sourcemap=inline --outfile=runtime_debug.js --define:DEBUG=true
|
||||
|
||||
build:production:
|
||||
internal: true
|
||||
cmds:
|
||||
- npx esbuild desktop/main.js --bundle --tree-shaking=true --minify --outfile=runtime_production_desktop_{{.PLATFORM}}.js --define:DEBUG=false --define:WINDOWS={{.WINDOWS}} --define:DARWIN={{.DARWIN}} --define:LINUX={{.LINUX}} --define:PLATFORM={{.PLATFORM}} --define:INVOKE={{.INVOKE}}
|
||||
|
||||
build:production:windows:
|
||||
cmds:
|
||||
- task: build:production
|
||||
vars:
|
||||
WINDOWS: true
|
||||
DARWIN: false
|
||||
LINUX: false
|
||||
PLATFORM: windows
|
||||
INVOKE: "chrome.webview.postMessage"
|
||||
|
||||
build:production:linux:
|
||||
cmds:
|
||||
- task: build:production
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: false
|
||||
LINUX: true
|
||||
PLATFORM: linux
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
|
||||
build:production:darwin:
|
||||
cmds:
|
||||
- task: build:production
|
||||
vars:
|
||||
WINDOWS: false
|
||||
DARWIN: true
|
||||
LINUX: false
|
||||
PLATFORM: darwin
|
||||
INVOKE: "webkit.messageHandlers.external.postMessage"
|
||||
- npx esbuild@latest desktop/main.js --bundle --tree-shaking=true --minify --outfile=runtime.js --drop:console
|
||||
|
||||
build:all:
|
||||
internal: true
|
||||
deps:
|
||||
- build:debug:windows
|
||||
- build:debug:linux
|
||||
- build:debug:darwin
|
||||
- build:production:windows
|
||||
- build:production:linux
|
||||
- build:production:darwin
|
||||
- build:debug
|
||||
- build:production
|
||||
|
||||
cmds:
|
||||
- cmd: echo "Build Complete."
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
package runtime
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed runtime.js
|
||||
var DesktopRuntime []byte
|
||||
|
||||
var RuntimeAssetsBundle = &RuntimeAssets{
|
||||
runtimeDesktopJS: DesktopRuntime,
|
||||
}
|
||||
|
||||
@@ -2,6 +2,11 @@
|
||||
|
||||
package runtime
|
||||
|
||||
import _ "embed"
|
||||
|
||||
//go:embed runtime_debug.js
|
||||
var DesktopRuntime []byte
|
||||
|
||||
var RuntimeAssetsBundle = &RuntimeAssets{
|
||||
runtimeDesktopJS: DesktopRuntime,
|
||||
}
|
||||
|
||||
@@ -0,0 +1,46 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import { newRuntimeCallerWithID, objectNames } from "./runtime";
|
||||
const call = newRuntimeCallerWithID(objectNames.Application);
|
||||
|
||||
const HideMethod = 0;
|
||||
const ShowMethod = 1;
|
||||
const QuitMethod = 2;
|
||||
|
||||
/**
|
||||
* Hides a certain method by calling the HideMethod function.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
*
|
||||
*/
|
||||
export function Hide() {
|
||||
return call(HideMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the ShowMethod and returns the result.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
export function Show() {
|
||||
return call(ShowMethod);
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls the QuitMethod to terminate the program.
|
||||
*
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
export function Quit() {
|
||||
return call(QuitMethod);
|
||||
}
|
||||
+4
-5
@@ -9,17 +9,16 @@ The electron alternative for Go
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
|
||||
let call = newRuntimeCallerWithID(objectNames.Browser);
|
||||
|
||||
let BrowserOpenURL = 0;
|
||||
const call = newRuntimeCallerWithID(objectNames.Browser, '');
|
||||
const BrowserOpenURL = 0;
|
||||
|
||||
/**
|
||||
* Open a browser window to the given URL
|
||||
* @param {string} url - The URL to open
|
||||
* @returns {Promise<string>}
|
||||
*/
|
||||
export function OpenURL(url) {
|
||||
void call(BrowserOpenURL, {url});
|
||||
return call(BrowserOpenURL, {url});
|
||||
}
|
||||
@@ -0,0 +1,123 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
import { newRuntimeCallerWithID, objectNames } from "./runtime";
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
|
||||
const CallBinding = 0;
|
||||
const call = newRuntimeCallerWithID(objectNames.Call, '');
|
||||
let callResponses = new Map();
|
||||
|
||||
window._wails = window._wails || {};
|
||||
window._wails.callCallback = resultHandler;
|
||||
window._wails.callErrorCallback = errorHandler;
|
||||
|
||||
function generateID() {
|
||||
let result;
|
||||
do {
|
||||
result = nanoid();
|
||||
} while (callResponses.has(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
export function resultHandler(id, data, isJSON) {
|
||||
const promiseHandler = getAndDeleteResponse(id);
|
||||
if (promiseHandler) {
|
||||
promiseHandler.resolve(isJSON ? JSON.parse(data) : data);
|
||||
}
|
||||
}
|
||||
|
||||
export function errorHandler(id, message) {
|
||||
const promiseHandler = getAndDeleteResponse(id);
|
||||
if (promiseHandler) {
|
||||
promiseHandler.reject(message);
|
||||
}
|
||||
}
|
||||
|
||||
function getAndDeleteResponse(id) {
|
||||
const response = callResponses.get(id);
|
||||
callResponses.delete(id);
|
||||
return response;
|
||||
}
|
||||
|
||||
function callBinding(type, options = {}) {
|
||||
return new Promise((resolve, reject) => {
|
||||
const id = generateID();
|
||||
options["call-id"] = id;
|
||||
callResponses.set(id, { resolve, reject });
|
||||
call(type, options).catch((error) => {
|
||||
reject(error);
|
||||
callResponses.delete(id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Call method.
|
||||
*
|
||||
* @param {Object} options - The options for the method.
|
||||
* @returns {Object} - The result of the call.
|
||||
*/
|
||||
export function Call(options) {
|
||||
return callBinding(CallBinding, options);
|
||||
}
|
||||
|
||||
/**
|
||||
* Executes a method by name.
|
||||
*
|
||||
* @param {string} name - The name of the method in the format 'package.struct.method'.
|
||||
* @param {...*} args - The arguments to pass to the method.
|
||||
* @throws {Error} If the name is not a string or is not in the correct format.
|
||||
* @returns {*} The result of the method execution.
|
||||
*/
|
||||
export function ByName(name, ...args) {
|
||||
if (typeof name !== "string" || name.split(".").length !== 3) {
|
||||
throw new Error("CallByName requires a string in the format 'package.struct.method'");
|
||||
}
|
||||
let [packageName, structName, methodName] = name.split(".");
|
||||
return callBinding(CallBinding, {
|
||||
packageName,
|
||||
structName,
|
||||
methodName,
|
||||
args
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a method by its ID with the specified arguments.
|
||||
*
|
||||
* @param {string} methodID - The ID of the method to call.
|
||||
* @param {...*} args - The arguments to pass to the method.
|
||||
* @return {*} - The result of the method call.
|
||||
*/
|
||||
export function ByID(methodID, ...args) {
|
||||
return callBinding(CallBinding, {
|
||||
methodID,
|
||||
args
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Calls a method on a plugin.
|
||||
*
|
||||
* @param {string} pluginName - The name of the plugin.
|
||||
* @param {string} methodName - The name of the method to call.
|
||||
* @param {...*} args - The arguments to pass to the method.
|
||||
* @returns {*} - The result of the method call.
|
||||
*/
|
||||
export function Plugin(pluginName, methodName, ...args) {
|
||||
return callBinding(CallBinding, {
|
||||
packageName: "wails-plugins",
|
||||
structName: pluginName,
|
||||
methodName,
|
||||
args
|
||||
});
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
|
||||
const call = newRuntimeCallerWithID(objectNames.Clipboard, '');
|
||||
const ClipboardSetText = 0;
|
||||
const ClipboardText = 1;
|
||||
|
||||
/**
|
||||
* Sets the text to the Clipboard.
|
||||
*
|
||||
* @param {string} text - The text to be set to the Clipboard.
|
||||
* @return {Promise} - A Promise that resolves when the operation is successful.
|
||||
*/
|
||||
export function SetText(text) {
|
||||
return call(ClipboardSetText, {text});
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the Clipboard text
|
||||
* @returns {Promise<string>} A promise that resolves with the text from the Clipboard.
|
||||
*/
|
||||
export function Text() {
|
||||
return call(ClipboardText);
|
||||
}
|
||||
+14
-3
@@ -1,8 +1,19 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
|
||||
let call = newRuntimeCallerWithID(objectNames.ContextMenu);
|
||||
|
||||
let ContextMenuOpen = 0;
|
||||
const call = newRuntimeCallerWithID(objectNames.ContextMenu, '');
|
||||
const ContextMenuOpen = 0;
|
||||
|
||||
function openContextMenu(id, x, y, data) {
|
||||
void call(ContextMenuOpen, {id, x, y, data});
|
||||
@@ -0,0 +1,138 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
/**
|
||||
* @typedef {import("./types").MessageDialogOptions} MessageDialogOptions
|
||||
* @typedef {import("./types").OpenDialogOptions} OpenDialogOptions
|
||||
* @typedef {import("./types").SaveDialogOptions} SaveDialogOptions
|
||||
*/
|
||||
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
|
||||
// Define constants from the `methods` object in Title Case
|
||||
const DialogInfo = 0;
|
||||
const DialogWarning = 1;
|
||||
const DialogError = 2;
|
||||
const DialogQuestion = 3;
|
||||
const DialogOpenFile = 4;
|
||||
const DialogSaveFile = 5;
|
||||
|
||||
const call = newRuntimeCallerWithID(objectNames.Dialog, '');
|
||||
const dialogResponses = new Map();
|
||||
|
||||
/**
|
||||
* Generates a unique id that is not present in dialogResponses.
|
||||
* @returns {string} unique id
|
||||
*/
|
||||
function generateID() {
|
||||
let result;
|
||||
do {
|
||||
result = nanoid();
|
||||
} while (dialogResponses.has(result));
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Shows a dialog of specified type with the given options.
|
||||
* @param {number} type - type of dialog
|
||||
* @param {object} options - options for the dialog
|
||||
* @returns {Promise} promise that resolves with result of dialog
|
||||
*/
|
||||
function dialog(type, options = {}) {
|
||||
const id = generateID();
|
||||
options["dialog-id"] = id;
|
||||
return new Promise((resolve, reject) => {
|
||||
dialogResponses.set(id, {resolve, reject});
|
||||
call(type, options).catch((error) => {
|
||||
reject(error);
|
||||
dialogResponses.delete(id);
|
||||
});
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Handles the callback from a dialog.
|
||||
*
|
||||
* @param {string} id - The ID of the dialog response.
|
||||
* @param {string} data - The data received from the dialog.
|
||||
* @param {boolean} isJSON - Flag indicating whether the data is in JSON format.
|
||||
*
|
||||
* @return {undefined}
|
||||
*/
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Callback function for handling errors in dialog.
|
||||
*
|
||||
* @param {string} id - The id of the dialog response.
|
||||
* @param {string} message - The error message.
|
||||
*
|
||||
* @return {void}
|
||||
*/
|
||||
export function dialogErrorCallback(id, message) {
|
||||
let p = dialogResponses.get(id);
|
||||
if (p) {
|
||||
p.reject(message);
|
||||
dialogResponses.delete(id);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
// Replace `methods` with constants in Title Case
|
||||
|
||||
/**
|
||||
* @param {MessageDialogOptions} options - Dialog options
|
||||
* @returns {Promise<string>} - The label of the button pressed
|
||||
*/
|
||||
export const Info = (options) => dialog(DialogInfo, options);
|
||||
|
||||
/**
|
||||
* @param {MessageDialogOptions} options - Dialog options
|
||||
* @returns {Promise<string>} - The label of the button pressed
|
||||
*/
|
||||
export const Warning = (options) => dialog(DialogWarning, options);
|
||||
|
||||
/**
|
||||
* @param {MessageDialogOptions} options - Dialog options
|
||||
* @returns {Promise<string>} - The label of the button pressed
|
||||
*/
|
||||
export const Error = (options) => dialog(DialogError, options);
|
||||
|
||||
/**
|
||||
* @param {MessageDialogOptions} options - Dialog options
|
||||
* @returns {Promise<string>} - The label of the button pressed
|
||||
*/
|
||||
export const Question = (options) => dialog(DialogQuestion, options);
|
||||
|
||||
/**
|
||||
* @param {OpenDialogOptions} options - Dialog options
|
||||
* @returns {Promise<string[]|string>} Returns selected file or list of files. Returns blank string if no file is selected.
|
||||
*/
|
||||
export const OpenFile = (options) => dialog(DialogOpenFile, options);
|
||||
|
||||
/**
|
||||
* @param {SaveDialogOptions} options - Dialog options
|
||||
* @returns {Promise<string>} Returns the selected file. Returns blank string if no file is selected.
|
||||
*/
|
||||
export const SaveFile = (options) => dialog(DialogSaveFile, options);
|
||||
+35
-53
@@ -10,26 +10,22 @@ The electron alternative for Go
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {invoke} from "./invoke";
|
||||
import {invoke, IsWindows} from "./system";
|
||||
import {GetFlag} from "./flags";
|
||||
|
||||
let shouldDrag = false;
|
||||
let resizeEdge = null;
|
||||
let resizable = false;
|
||||
let defaultCursor = "auto";
|
||||
window._wails = window._wails || {};
|
||||
window._wails.setResizable = setResizable;
|
||||
window._wails.endDrag = endDrag;
|
||||
|
||||
export function dragTest(e) {
|
||||
let val = window.getComputedStyle(e.target).getPropertyValue("--webkit-app-region");
|
||||
if (val) {
|
||||
val = val.trim();
|
||||
}
|
||||
|
||||
if (val !== "drag") {
|
||||
if (val && val.trim() !== "drag" || e.buttons !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
// Only process the primary button
|
||||
if (e.buttons !== 1) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return e.detail === 1;
|
||||
}
|
||||
|
||||
@@ -39,38 +35,32 @@ export function setupDrag() {
|
||||
window.addEventListener('mouseup', onMouseUp);
|
||||
}
|
||||
|
||||
let resizeEdge = null;
|
||||
let resizable = false;
|
||||
|
||||
export function setResizable(value) {
|
||||
resizable = value;
|
||||
}
|
||||
|
||||
function testResize(e) {
|
||||
export function endDrag() {
|
||||
document.body.style.cursor = 'default';
|
||||
shouldDrag = false;
|
||||
}
|
||||
|
||||
function testResize() {
|
||||
if( resizeEdge ) {
|
||||
invoke("resize:" + resizeEdge);
|
||||
invoke(`resize:${resizeEdge}`);
|
||||
return true
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
function onMouseDown(e) {
|
||||
if(IsWindows() && testResize() || dragTest(e)) {
|
||||
shouldDrag = !!isValidDrag(e);
|
||||
}
|
||||
}
|
||||
|
||||
// Check for resizing on Windows
|
||||
if( WINDOWS ) {
|
||||
if (testResize()) {
|
||||
return;
|
||||
}
|
||||
}
|
||||
if (dragTest(e)) {
|
||||
// Ignore drag on scrollbars
|
||||
if (e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight) {
|
||||
return;
|
||||
}
|
||||
shouldDrag = true;
|
||||
} else {
|
||||
shouldDrag = false;
|
||||
}
|
||||
function isValidDrag(e) {
|
||||
// Ignore drag on scrollbars
|
||||
return !(e.offsetX > e.target.clientWidth || e.offsetY > e.target.clientHeight);
|
||||
}
|
||||
|
||||
function onMouseUp(e) {
|
||||
@@ -80,34 +70,26 @@ function onMouseUp(e) {
|
||||
}
|
||||
}
|
||||
|
||||
export function endDrag() {
|
||||
document.body.style.cursor = 'default';
|
||||
shouldDrag = false;
|
||||
}
|
||||
|
||||
function setResize(cursor) {
|
||||
document.documentElement.style.cursor = cursor || defaultCursor;
|
||||
function setResize(cursor = defaultCursor) {
|
||||
document.documentElement.style.cursor = cursor;
|
||||
resizeEdge = cursor;
|
||||
}
|
||||
|
||||
function onMouseMove(e) {
|
||||
if (shouldDrag) {
|
||||
shouldDrag = false;
|
||||
let mousePressed = e.buttons !== undefined ? e.buttons : e.which;
|
||||
if (mousePressed > 0) {
|
||||
invoke("drag");
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
if (WINDOWS) {
|
||||
if (resizable) {
|
||||
handleResize(e);
|
||||
}
|
||||
shouldDrag = checkDrag(e);
|
||||
if (IsWindows() && resizable) {
|
||||
handleResize(e);
|
||||
}
|
||||
}
|
||||
|
||||
let defaultCursor = "auto";
|
||||
function checkDrag(e) {
|
||||
let mousePressed = e.buttons !== undefined ? e.buttons : e.which;
|
||||
if(shouldDrag && mousePressed > 0) {
|
||||
invoke("drag");
|
||||
return false;
|
||||
}
|
||||
return shouldDrag;
|
||||
}
|
||||
|
||||
function handleResize(e) {
|
||||
let resizeHandleHeight = GetFlag("system.resizeHandleHeight") || 5;
|
||||
@@ -0,0 +1,134 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
/**
|
||||
* @typedef {import("./types").WailsEvent} WailsEvent
|
||||
*/
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
|
||||
const call = newRuntimeCallerWithID(objectNames.Events, '');
|
||||
const EmitMethod = 0;
|
||||
const eventListeners = new Map();
|
||||
|
||||
class Listener {
|
||||
constructor(eventName, callback, maxCallbacks) {
|
||||
this.eventName = eventName;
|
||||
this.maxCallbacks = maxCallbacks || -1;
|
||||
this.Callback = (data) => {
|
||||
callback(data);
|
||||
if (this.maxCallbacks === -1) return false;
|
||||
this.maxCallbacks -= 1;
|
||||
return this.maxCallbacks === 0;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
export class WailsEvent {
|
||||
constructor(name, data = null) {
|
||||
this.name = name;
|
||||
this.data = data;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
window._wails = window._wails || {};
|
||||
window._wails.dispatchWailsEvent = dispatchWailsEvent;
|
||||
|
||||
export function dispatchWailsEvent(event) {
|
||||
let listeners = eventListeners.get(event.name);
|
||||
if (listeners) {
|
||||
let toRemove = listeners.filter(listener => {
|
||||
let remove = listener.Callback(event);
|
||||
if (remove) return true;
|
||||
});
|
||||
if (toRemove.length > 0) {
|
||||
listeners = listeners.filter(l => !toRemove.includes(l));
|
||||
if (listeners.length === 0) eventListeners.delete(event.name);
|
||||
else eventListeners.set(event.name, listeners);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a callback function to be called multiple times for a specific event.
|
||||
*
|
||||
* @param {string} eventName - The name of the event to register the callback for.
|
||||
* @param {function} callback - The callback function to be called when the event is triggered.
|
||||
* @param {number} maxCallbacks - The maximum number of times the callback can be called for the event. Once the maximum number is reached, the callback will no longer be called.
|
||||
*
|
||||
@return {function} - A function that, when called, will unregister the callback from the event.
|
||||
*/
|
||||
export function OnMultiple(eventName, callback, maxCallbacks) {
|
||||
let listeners = eventListeners.get(eventName) || [];
|
||||
const thisListener = new Listener(eventName, callback, maxCallbacks);
|
||||
listeners.push(thisListener);
|
||||
eventListeners.set(eventName, listeners);
|
||||
return () => listenerOff(thisListener);
|
||||
}
|
||||
|
||||
/**
|
||||
* Registers a callback function to be executed when the specified event occurs.
|
||||
*
|
||||
* @param {string} eventName - The name of the event.
|
||||
* @param {function} callback - The callback function to be executed. It takes no parameters.
|
||||
* @return {function} - A function that, when called, will unregister the callback from the event. */
|
||||
export function On(eventName, callback) { return OnMultiple(eventName, callback, -1); }
|
||||
|
||||
/**
|
||||
* Registers a callback function to be executed only once for the specified event.
|
||||
*
|
||||
* @param {string} eventName - The name of the event.
|
||||
* @param {function} callback - The function to be executed when the event occurs.
|
||||
* @return {void@return {function} - A function that, when called, will unregister the callback from the event.
|
||||
*/
|
||||
export function Once(eventName, callback) { return OnMultiple(eventName, callback, 1); }
|
||||
|
||||
/**
|
||||
* Removes the specified listener from the event listeners collection.
|
||||
* If all listeners for the event are removed, the event key is deleted from the collection.
|
||||
*
|
||||
* @param {Object} listener - The listener to be removed.
|
||||
*/
|
||||
function listenerOff(listener) {
|
||||
const eventName = listener.eventName;
|
||||
let listeners = eventListeners.get(eventName).filter(l => l !== listener);
|
||||
if (listeners.length === 0) eventListeners.delete(eventName);
|
||||
else eventListeners.set(eventName, listeners);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Removes event listeners for the specified event names.
|
||||
*
|
||||
* @param {string} eventName - The name of the event to remove listeners for.
|
||||
* @param {...string} additionalEventNames - Additional event names to remove listeners for.
|
||||
* @return {undefined}
|
||||
*/
|
||||
export function Off(eventName, ...additionalEventNames) {
|
||||
let eventsToRemove = [eventName, ...additionalEventNames];
|
||||
eventsToRemove.forEach(eventName => eventListeners.delete(eventName));
|
||||
}
|
||||
/**
|
||||
* Removes all event listeners.
|
||||
*
|
||||
* @function OffAll
|
||||
* @returns {void}
|
||||
*/
|
||||
export function OffAll() { eventListeners.clear(); }
|
||||
|
||||
/**
|
||||
* Emits an event using the given event name.
|
||||
*
|
||||
* @param {WailsEvent} event - The name of the event to emit.
|
||||
* @returns {any} - The result of the emitted event.
|
||||
*/
|
||||
export function Emit(event) { return call(EmitMethod, event); }
|
||||
+2
@@ -1,4 +1,6 @@
|
||||
|
||||
import { On, Off, OffAll, OnMultiple, WailsEvent, dispatchWailsEvent, eventListeners, Once } from './events';
|
||||
|
||||
import { expect, describe, it, vi, afterEach, beforeEach } from 'vitest';
|
||||
|
||||
afterEach(() => {
|
||||
+6
@@ -52,6 +52,12 @@ function getValueFromMap(keyString) {
|
||||
return value;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retrieves the value associated with the specified key from the flag map.
|
||||
*
|
||||
* @param {string} keyString - The key to retrieve the value for.
|
||||
* @return {*} - The value associated with the specified key.
|
||||
*/
|
||||
export function GetFlag(keyString) {
|
||||
return getValueFromMap(keyString);
|
||||
}
|
||||
@@ -0,0 +1,56 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
import {setupContextMenus} from "./contextmenu";
|
||||
import {setupDrag} from "./drag";
|
||||
import {reloadWML} from "./wml";
|
||||
import {Emit, Off, OffAll, On, Once, OnMultiple, WailsEvent} from './events';
|
||||
import {ByID, ByName, Plugin} from "./calls";
|
||||
import {Error, Info, OpenFile, Question, SaveFile, Warning} from "./dialogs";
|
||||
|
||||
export * as Application from "./application";
|
||||
export * as Browser from "./browser";
|
||||
export * as Clipboard from "./clipboard";
|
||||
export * as ContextMenu from "./contextmenu";
|
||||
export * as Flags from "./flags";
|
||||
export * as Runtime from "./runtime";
|
||||
export * as Screens from "./screens";
|
||||
export * as System from "./system";
|
||||
export * as Window from "./window";
|
||||
|
||||
export const Events = {
|
||||
On,
|
||||
Off,
|
||||
OnMultiple,
|
||||
WailsEvent,
|
||||
OffAll,
|
||||
Emit,
|
||||
Once
|
||||
|
||||
}
|
||||
|
||||
export const Call = {
|
||||
Plugin,
|
||||
ByID,
|
||||
ByName
|
||||
}
|
||||
|
||||
export const Dialogs = {
|
||||
Info,
|
||||
Error,
|
||||
OpenFile, Question, Warning, SaveFile
|
||||
}
|
||||
|
||||
setupContextMenus();
|
||||
setupDrag();
|
||||
|
||||
document.addEventListener("DOMContentLoaded", function () {
|
||||
reloadWML();
|
||||
});
|
||||
+2
-2
@@ -1,7 +1,7 @@
|
||||
{
|
||||
"name": "@wailsapp/api",
|
||||
"name": "@wailsio/runtime",
|
||||
"version": "3.0.0-alpha.4",
|
||||
"description": "Wails Runtime API",
|
||||
"description": "Wails Runtime",
|
||||
"main": "index.js",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
+28
-12
@@ -12,6 +12,7 @@ The electron alternative for Go
|
||||
import { nanoid } from 'nanoid/non-secure';
|
||||
|
||||
const runtimeURL = window.location.origin + "/wails/runtime";
|
||||
|
||||
// Object Names
|
||||
export const objectNames = {
|
||||
Call: 0,
|
||||
@@ -27,6 +28,33 @@ export const objectNames = {
|
||||
}
|
||||
export let clientId = nanoid();
|
||||
|
||||
/**
|
||||
* Creates a runtime caller function that invokes a specified method on a given object within a specified window context.
|
||||
*
|
||||
* @param {Object} object - The object on which the method is to be invoked.
|
||||
* @param {string} windowName - The name of the window context in which the method should be called.
|
||||
* @returns {Function} A runtime caller function that takes the method name and optionally arguments and invokes the method within the specified window context.
|
||||
*/
|
||||
export function newRuntimeCaller(object, windowName) {
|
||||
return function (method, args=null) {
|
||||
return runtimeCall(object + "." + method, windowName, args);
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Creates a new runtime caller with specified ID.
|
||||
*
|
||||
* @param {object} object - The object to invoke the method on.
|
||||
* @param {string} windowName - The name of the window.
|
||||
* @return {Function} - The new runtime caller function.
|
||||
*/
|
||||
export function newRuntimeCallerWithID(object, windowName) {
|
||||
return function (method, args=null) {
|
||||
return runtimeCallWithID(object, method, windowName, args);
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function runtimeCall(method, windowName, args) {
|
||||
let url = new URL(runtimeURL);
|
||||
if( method ) {
|
||||
@@ -61,12 +89,6 @@ function runtimeCall(method, windowName, args) {
|
||||
});
|
||||
}
|
||||
|
||||
export function newRuntimeCaller(object, windowName) {
|
||||
return function (method, args=null) {
|
||||
return runtimeCall(object + "." + method, windowName, args);
|
||||
};
|
||||
}
|
||||
|
||||
function runtimeCallWithID(objectID, method, windowName, args) {
|
||||
let url = new URL(runtimeURL);
|
||||
url.searchParams.append("object", objectID);
|
||||
@@ -98,9 +120,3 @@ function runtimeCallWithID(objectID, method, windowName, args) {
|
||||
.catch(error => reject(error));
|
||||
});
|
||||
}
|
||||
|
||||
export function newRuntimeCallerWithID(object, windowName) {
|
||||
return function (method, args=null) {
|
||||
return runtimeCallWithID(object, method, windowName, args);
|
||||
};
|
||||
}
|
||||
+11
-14
@@ -15,34 +15,31 @@ The electron alternative for Go
|
||||
*/
|
||||
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
const call = newRuntimeCallerWithID(objectNames.Screens, '');
|
||||
|
||||
let call = newRuntimeCallerWithID(objectNames.Screens);
|
||||
|
||||
let ScreensGetAll = 0;
|
||||
let ScreensGetPrimary = 1;
|
||||
let ScreensGetCurrent = 2;
|
||||
const getAll = 0;
|
||||
const getPrimary = 1;
|
||||
const getCurrent = 2;
|
||||
|
||||
/**
|
||||
* Gets all screens.
|
||||
* @returns {Promise<Screen[]>}
|
||||
* @returns {Promise<Screen[]>} A promise that resolves to an array of Screen objects.
|
||||
*/
|
||||
export function GetAll() {
|
||||
return call(ScreensGetAll);
|
||||
return call(getAll);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the primary screen.
|
||||
* @returns {Promise<Screen>}
|
||||
* @returns {Promise<Screen>} A promise that resolves to the primary screen.
|
||||
*/
|
||||
export function GetPrimary() {
|
||||
return call(ScreensGetPrimary);
|
||||
return call(getPrimary);
|
||||
}
|
||||
|
||||
/**
|
||||
* Gets the current active screen.
|
||||
* @returns {Promise<Screen>}
|
||||
* @constructor
|
||||
*
|
||||
* @returns {Promise<Screen>} A promise that resolves with the current active screen.
|
||||
*/
|
||||
export function GetCurrent() {
|
||||
return call(ScreensGetCurrent);
|
||||
return call(getCurrent);
|
||||
}
|
||||
@@ -0,0 +1,118 @@
|
||||
/*
|
||||
_ __ _ __
|
||||
| | / /___ _(_) /____
|
||||
| | /| / / __ `/ / / ___/
|
||||
| |/ |/ / /_/ / / (__ )
|
||||
|__/|__/\__,_/_/_/____/
|
||||
The electron alternative for Go
|
||||
(c) Lea Anthony 2019-present
|
||||
*/
|
||||
|
||||
/* jshint esversion: 9 */
|
||||
|
||||
import {newRuntimeCallerWithID, objectNames} from "./runtime";
|
||||
let call = newRuntimeCallerWithID(objectNames.System, '');
|
||||
const systemIsDarkMode = 0;
|
||||
const environment = 1;
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Retrieves the system dark mode status.
|
||||
* @returns {Promise<boolean>} - A promise that resolves to a boolean value indicating if the system is in dark mode.
|
||||
*/
|
||||
export function IsDarkMode() {
|
||||
return call(systemIsDarkMode);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* Fetches the capabilities of the application from the server.
|
||||
*
|
||||
* @async
|
||||
* @function Capabilities
|
||||
* @returns {Promise<Object>} A promise that resolves to an object containing the capabilities.
|
||||
*/
|
||||
export async function Capabilities() {
|
||||
let response = fetch("/wails/capabilities");
|
||||
return response.json();
|
||||
}
|
||||
|
||||
/**
|
||||
* @typedef {object} EnvironmentInfo
|
||||
* @property {string} OS - The operating system in use.
|
||||
* @property {string} Arch - The architecture of the system.
|
||||
*/
|
||||
|
||||
/**
|
||||
* @function
|
||||
* Retrieves environment details.
|
||||
* @returns {Promise<EnvironmentInfo>} - A promise that resolves to an object containing OS and system architecture.
|
||||
*/
|
||||
export function Environment() {
|
||||
return call(environment);
|
||||
}
|
||||
|
||||
export let invoke = null;
|
||||
let environmentCache = null;
|
||||
|
||||
Environment()
|
||||
.then(result => {
|
||||
environmentCache = result;
|
||||
invoke = IsWindows() ? window.chrome.webview.postMessage : window.webkit.messageHandlers.external.postMessage;
|
||||
})
|
||||
.catch(error => {
|
||||
console.error(`Error getting Environment: ${error}`);
|
||||
});
|
||||
|
||||
/**
|
||||
* Checks if the current operating system is Windows.
|
||||
*
|
||||
* @return {boolean} True if the operating system is Windows, otherwise false.
|
||||
*/
|
||||
export function IsWindows() {
|
||||
return environmentCache.OS === "windows";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current operating system is Linux.
|
||||
*
|
||||
* @returns {boolean} Returns true if the current operating system is Linux, false otherwise.
|
||||
*/
|
||||
export function IsLinux() {
|
||||
return environmentCache.OS === "linux";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current environment is a macOS operating system.
|
||||
*
|
||||
* @returns {boolean} True if the environment is macOS, false otherwise.
|
||||
*/
|
||||
export function IsMac() {
|
||||
return environmentCache.OS === "darwin";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current environment architecture is AMD64.
|
||||
* @returns {boolean} True if the current environment architecture is AMD64, false otherwise.
|
||||
*/
|
||||
export function IsAMD64() {
|
||||
return environmentCache.Arch === "amd64";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current architecture is ARM.
|
||||
*
|
||||
* @returns {boolean} True if the current architecture is ARM, false otherwise.
|
||||
*/
|
||||
export function IsARM() {
|
||||
return environmentCache.Arch === "arm";
|
||||
}
|
||||
|
||||
/**
|
||||
* Checks if the current environment is ARM64 architecture.
|
||||
*
|
||||
* @returns {boolean} - Returns true if the environment is ARM64 architecture, otherwise returns false.
|
||||
*/
|
||||
export function IsARM64() {
|
||||
return environmentCache.Arch === "arm64";
|
||||
}
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user