@wailsio/runtime 3.0.0-alpha.4

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/events.js ADDED
@@ -0,0 +1,134 @@
1
+ /*
2
+ _ __ _ __
3
+ | | / /___ _(_) /____
4
+ | | /| / / __ `/ / / ___/
5
+ | |/ |/ / /_/ / / (__ )
6
+ |__/|__/\__,_/_/_/____/
7
+ The electron alternative for Go
8
+ (c) Lea Anthony 2019-present
9
+ */
10
+
11
+ /* jshint esversion: 9 */
12
+
13
+ /**
14
+ * @typedef {import("./types").WailsEvent} WailsEvent
15
+ */
16
+ import {newRuntimeCallerWithID, objectNames} from "./runtime";
17
+
18
+ const call = newRuntimeCallerWithID(objectNames.Events, '');
19
+ const EmitMethod = 0;
20
+ const eventListeners = new Map();
21
+
22
+ class Listener {
23
+ constructor(eventName, callback, maxCallbacks) {
24
+ this.eventName = eventName;
25
+ this.maxCallbacks = maxCallbacks || -1;
26
+ this.Callback = (data) => {
27
+ callback(data);
28
+ if (this.maxCallbacks === -1) return false;
29
+ this.maxCallbacks -= 1;
30
+ return this.maxCallbacks === 0;
31
+ };
32
+ }
33
+ }
34
+
35
+ export class WailsEvent {
36
+ constructor(name, data = null) {
37
+ this.name = name;
38
+ this.data = data;
39
+ }
40
+ }
41
+
42
+
43
+ window._wails = window._wails || {};
44
+ window._wails.dispatchWailsEvent = dispatchWailsEvent;
45
+
46
+ export function dispatchWailsEvent(event) {
47
+ let listeners = eventListeners.get(event.name);
48
+ if (listeners) {
49
+ let toRemove = listeners.filter(listener => {
50
+ let remove = listener.Callback(event);
51
+ if (remove) return true;
52
+ });
53
+ if (toRemove.length > 0) {
54
+ listeners = listeners.filter(l => !toRemove.includes(l));
55
+ if (listeners.length === 0) eventListeners.delete(event.name);
56
+ else eventListeners.set(event.name, listeners);
57
+ }
58
+ }
59
+ }
60
+
61
+ /**
62
+ * Register a callback function to be called multiple times for a specific event.
63
+ *
64
+ * @param {string} eventName - The name of the event to register the callback for.
65
+ * @param {function} callback - The callback function to be called when the event is triggered.
66
+ * @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.
67
+ *
68
+ @return {function} - A function that, when called, will unregister the callback from the event.
69
+ */
70
+ export function OnMultiple(eventName, callback, maxCallbacks) {
71
+ let listeners = eventListeners.get(eventName) || [];
72
+ const thisListener = new Listener(eventName, callback, maxCallbacks);
73
+ listeners.push(thisListener);
74
+ eventListeners.set(eventName, listeners);
75
+ return () => listenerOff(thisListener);
76
+ }
77
+
78
+ /**
79
+ * Registers a callback function to be executed when the specified event occurs.
80
+ *
81
+ * @param {string} eventName - The name of the event.
82
+ * @param {function} callback - The callback function to be executed. It takes no parameters.
83
+ * @return {function} - A function that, when called, will unregister the callback from the event. */
84
+ export function On(eventName, callback) { return OnMultiple(eventName, callback, -1); }
85
+
86
+ /**
87
+ * Registers a callback function to be executed only once for the specified event.
88
+ *
89
+ * @param {string} eventName - The name of the event.
90
+ * @param {function} callback - The function to be executed when the event occurs.
91
+ * @return {void@return {function} - A function that, when called, will unregister the callback from the event.
92
+ */
93
+ export function Once(eventName, callback) { return OnMultiple(eventName, callback, 1); }
94
+
95
+ /**
96
+ * Removes the specified listener from the event listeners collection.
97
+ * If all listeners for the event are removed, the event key is deleted from the collection.
98
+ *
99
+ * @param {Object} listener - The listener to be removed.
100
+ */
101
+ function listenerOff(listener) {
102
+ const eventName = listener.eventName;
103
+ let listeners = eventListeners.get(eventName).filter(l => l !== listener);
104
+ if (listeners.length === 0) eventListeners.delete(eventName);
105
+ else eventListeners.set(eventName, listeners);
106
+ }
107
+
108
+
109
+ /**
110
+ * Removes event listeners for the specified event names.
111
+ *
112
+ * @param {string} eventName - The name of the event to remove listeners for.
113
+ * @param {...string} additionalEventNames - Additional event names to remove listeners for.
114
+ * @return {undefined}
115
+ */
116
+ export function Off(eventName, ...additionalEventNames) {
117
+ let eventsToRemove = [eventName, ...additionalEventNames];
118
+ eventsToRemove.forEach(eventName => eventListeners.delete(eventName));
119
+ }
120
+ /**
121
+ * Removes all event listeners.
122
+ *
123
+ * @function OffAll
124
+ * @returns {void}
125
+ */
126
+ export function OffAll() { eventListeners.clear(); }
127
+
128
+ /**
129
+ * Emits an event using the given event name.
130
+ *
131
+ * @param {WailsEvent} event - The name of the event to emit.
132
+ * @returns {any} - The result of the emitted event.
133
+ */
134
+ export function Emit(event) { return call(EmitMethod, event); }
package/flags.js ADDED
@@ -0,0 +1,63 @@
1
+ /*
2
+ _ __ _ __
3
+ | | / /___ _(_) /____
4
+ | | /| / / __ `/ / / ___/
5
+ | |/ |/ / /_/ / / (__ )
6
+ |__/|__/\__,_/_/_/____/
7
+ The electron alternative for Go
8
+ (c) Lea Anthony 2019-present
9
+ */
10
+
11
+ /* jshint esversion: 9 */
12
+
13
+ let flags = new Map();
14
+
15
+ function convertToMap(obj) {
16
+ const map = new Map();
17
+
18
+ for (const [key, value] of Object.entries(obj)) {
19
+ if (typeof value === 'object' && value !== null) {
20
+ map.set(key, convertToMap(value)); // Recursively convert nested object
21
+ } else {
22
+ map.set(key, value);
23
+ }
24
+ }
25
+
26
+ return map;
27
+ }
28
+
29
+ fetch("/wails/flags").then((response) => {
30
+ response.json().then((data) => {
31
+ flags = convertToMap(data);
32
+ });
33
+ });
34
+
35
+
36
+ function getValueFromMap(keyString) {
37
+ const keys = keyString.split('.');
38
+ let value = flags;
39
+
40
+ for (const key of keys) {
41
+ if (value instanceof Map) {
42
+ value = value.get(key);
43
+ } else {
44
+ value = value[key];
45
+ }
46
+
47
+ if (value === undefined) {
48
+ break;
49
+ }
50
+ }
51
+
52
+ return value;
53
+ }
54
+
55
+ /**
56
+ * Retrieves the value associated with the specified key from the flag map.
57
+ *
58
+ * @param {string} keyString - The key to retrieve the value for.
59
+ * @return {*} - The value associated with the specified key.
60
+ */
61
+ export function GetFlag(keyString) {
62
+ return getValueFromMap(keyString);
63
+ }
package/index.js ADDED
@@ -0,0 +1,56 @@
1
+ /*
2
+ _ __ _ __
3
+ | | / /___ _(_) /____
4
+ | | /| / / __ `/ / / ___/
5
+ | |/ |/ / /_/ / / (__ )
6
+ |__/|__/\__,_/_/_/____/
7
+ The electron alternative for Go
8
+ (c) Lea Anthony 2019-present
9
+ */
10
+
11
+ import {setupContextMenus} from "./contextmenu";
12
+ import {setupDrag} from "./drag";
13
+ import {reloadWML} from "./wml";
14
+ import {Emit, Off, OffAll, On, Once, OnMultiple, WailsEvent} from './events';
15
+ import {ByID, ByName, Plugin} from "./calls";
16
+ import {Error, Info, OpenFile, Question, SaveFile, Warning} from "./dialogs";
17
+
18
+ export * as Application from "./application";
19
+ export * as Browser from "./browser";
20
+ export * as Clipboard from "./clipboard";
21
+ export * as ContextMenu from "./contextmenu";
22
+ export * as Flags from "./flags";
23
+ export * as Runtime from "./runtime";
24
+ export * as Screens from "./screens";
25
+ export * as System from "./system";
26
+ export * as Window from "./window";
27
+
28
+ export const Events = {
29
+ On,
30
+ Off,
31
+ OnMultiple,
32
+ WailsEvent,
33
+ OffAll,
34
+ Emit,
35
+ Once
36
+
37
+ }
38
+
39
+ export const Call = {
40
+ Plugin,
41
+ ByID,
42
+ ByName
43
+ }
44
+
45
+ export const Dialogs = {
46
+ Info,
47
+ Error,
48
+ OpenFile, Question, Warning, SaveFile
49
+ }
50
+
51
+ setupContextMenus();
52
+ setupDrag();
53
+
54
+ document.addEventListener("DOMContentLoaded", function () {
55
+ reloadWML();
56
+ });
package/package.json ADDED
@@ -0,0 +1,17 @@
1
+ {
2
+ "name": "@wailsio/runtime",
3
+ "version": "3.0.0-alpha.4",
4
+ "description": "Wails Runtime",
5
+ "main": "index.js",
6
+ "repository": {
7
+ "type": "git",
8
+ "url": "https://github.com/wailsapp/wails.git"
9
+ },
10
+ "author": "The Wails Team",
11
+ "license": "MIT",
12
+ "bugs": {
13
+ "url": "https://github.com/wailsapp/wails/issues"
14
+ },
15
+ "homepage": "https://wails.io",
16
+ "private": false
17
+ }
package/runtime.js ADDED
@@ -0,0 +1,122 @@
1
+ /*
2
+ _ __ _ __
3
+ | | / /___ _(_) /____
4
+ | | /| / / __ `/ / / ___/
5
+ | |/ |/ / /_/ / / (__ )
6
+ |__/|__/\__,_/_/_/____/
7
+ The electron alternative for Go
8
+ (c) Lea Anthony 2019-present
9
+ */
10
+
11
+ /* jshint esversion: 9 */
12
+ import { nanoid } from 'nanoid/non-secure';
13
+
14
+ const runtimeURL = window.location.origin + "/wails/runtime";
15
+
16
+ // Object Names
17
+ export const objectNames = {
18
+ Call: 0,
19
+ Clipboard: 1,
20
+ Application: 2,
21
+ Events: 3,
22
+ ContextMenu: 4,
23
+ Dialog: 5,
24
+ Window: 6,
25
+ Screens: 7,
26
+ System: 8,
27
+ Browser: 9,
28
+ }
29
+ export let clientId = nanoid();
30
+
31
+ /**
32
+ * Creates a runtime caller function that invokes a specified method on a given object within a specified window context.
33
+ *
34
+ * @param {Object} object - The object on which the method is to be invoked.
35
+ * @param {string} windowName - The name of the window context in which the method should be called.
36
+ * @returns {Function} A runtime caller function that takes the method name and optionally arguments and invokes the method within the specified window context.
37
+ */
38
+ export function newRuntimeCaller(object, windowName) {
39
+ return function (method, args=null) {
40
+ return runtimeCall(object + "." + method, windowName, args);
41
+ };
42
+ }
43
+
44
+ /**
45
+ * Creates a new runtime caller with specified ID.
46
+ *
47
+ * @param {object} object - The object to invoke the method on.
48
+ * @param {string} windowName - The name of the window.
49
+ * @return {Function} - The new runtime caller function.
50
+ */
51
+ export function newRuntimeCallerWithID(object, windowName) {
52
+ return function (method, args=null) {
53
+ return runtimeCallWithID(object, method, windowName, args);
54
+ };
55
+ }
56
+
57
+
58
+ function runtimeCall(method, windowName, args) {
59
+ let url = new URL(runtimeURL);
60
+ if( method ) {
61
+ url.searchParams.append("method", method);
62
+ }
63
+ let fetchOptions = {
64
+ headers: {},
65
+ };
66
+ if (windowName) {
67
+ fetchOptions.headers["x-wails-window-name"] = windowName;
68
+ }
69
+ if (args) {
70
+ url.searchParams.append("args", JSON.stringify(args));
71
+ }
72
+ fetchOptions.headers["x-wails-client-id"] = clientId;
73
+
74
+ return new Promise((resolve, reject) => {
75
+ fetch(url, fetchOptions)
76
+ .then(response => {
77
+ if (response.ok) {
78
+ // check content type
79
+ if (response.headers.get("Content-Type") && response.headers.get("Content-Type").indexOf("application/json") !== -1) {
80
+ return response.json();
81
+ } else {
82
+ return response.text();
83
+ }
84
+ }
85
+ reject(Error(response.statusText));
86
+ })
87
+ .then(data => resolve(data))
88
+ .catch(error => reject(error));
89
+ });
90
+ }
91
+
92
+ function runtimeCallWithID(objectID, method, windowName, args) {
93
+ let url = new URL(runtimeURL);
94
+ url.searchParams.append("object", objectID);
95
+ url.searchParams.append("method", method);
96
+ let fetchOptions = {
97
+ headers: {},
98
+ };
99
+ if (windowName) {
100
+ fetchOptions.headers["x-wails-window-name"] = windowName;
101
+ }
102
+ if (args) {
103
+ url.searchParams.append("args", JSON.stringify(args));
104
+ }
105
+ fetchOptions.headers["x-wails-client-id"] = clientId;
106
+ return new Promise((resolve, reject) => {
107
+ fetch(url, fetchOptions)
108
+ .then(response => {
109
+ if (response.ok) {
110
+ // check content type
111
+ if (response.headers.get("Content-Type") && response.headers.get("Content-Type").indexOf("application/json") !== -1) {
112
+ return response.json();
113
+ } else {
114
+ return response.text();
115
+ }
116
+ }
117
+ reject(Error(response.statusText));
118
+ })
119
+ .then(data => resolve(data))
120
+ .catch(error => reject(error));
121
+ });
122
+ }
package/screens.js ADDED
@@ -0,0 +1,45 @@
1
+ /*
2
+ _ __ _ __
3
+ | | / /___ _(_) /____
4
+ | | /| / / __ `/ / / ___/
5
+ | |/ |/ / /_/ / / (__ )
6
+ |__/|__/\__,_/_/_/____/
7
+ The electron alternative for Go
8
+ (c) Lea Anthony 2019-present
9
+ */
10
+
11
+ /* jshint esversion: 9 */
12
+
13
+ /**
14
+ * @typedef {import("./api/types").Screen} Screen
15
+ */
16
+
17
+ import {newRuntimeCallerWithID, objectNames} from "./runtime";
18
+ const call = newRuntimeCallerWithID(objectNames.Screens, '');
19
+
20
+ const getAll = 0;
21
+ const getPrimary = 1;
22
+ const getCurrent = 2;
23
+
24
+ /**
25
+ * Gets all screens.
26
+ * @returns {Promise<Screen[]>} A promise that resolves to an array of Screen objects.
27
+ */
28
+ export function GetAll() {
29
+ return call(getAll);
30
+ }
31
+ /**
32
+ * Gets the primary screen.
33
+ * @returns {Promise<Screen>} A promise that resolves to the primary screen.
34
+ */
35
+ export function GetPrimary() {
36
+ return call(getPrimary);
37
+ }
38
+ /**
39
+ * Gets the current active screen.
40
+ *
41
+ * @returns {Promise<Screen>} A promise that resolves with the current active screen.
42
+ */
43
+ export function GetCurrent() {
44
+ return call(getCurrent);
45
+ }
package/system.js ADDED
@@ -0,0 +1,118 @@
1
+ /*
2
+ _ __ _ __
3
+ | | / /___ _(_) /____
4
+ | | /| / / __ `/ / / ___/
5
+ | |/ |/ / /_/ / / (__ )
6
+ |__/|__/\__,_/_/_/____/
7
+ The electron alternative for Go
8
+ (c) Lea Anthony 2019-present
9
+ */
10
+
11
+ /* jshint esversion: 9 */
12
+
13
+ import {newRuntimeCallerWithID, objectNames} from "./runtime";
14
+ let call = newRuntimeCallerWithID(objectNames.System, '');
15
+ const systemIsDarkMode = 0;
16
+ const environment = 1;
17
+
18
+ /**
19
+ * @function
20
+ * Retrieves the system dark mode status.
21
+ * @returns {Promise<boolean>} - A promise that resolves to a boolean value indicating if the system is in dark mode.
22
+ */
23
+ export function IsDarkMode() {
24
+ return call(systemIsDarkMode);
25
+ }
26
+
27
+
28
+ /**
29
+ * Fetches the capabilities of the application from the server.
30
+ *
31
+ * @async
32
+ * @function Capabilities
33
+ * @returns {Promise<Object>} A promise that resolves to an object containing the capabilities.
34
+ */
35
+ export async function Capabilities() {
36
+ let response = fetch("/wails/capabilities");
37
+ return response.json();
38
+ }
39
+
40
+ /**
41
+ * @typedef {object} EnvironmentInfo
42
+ * @property {string} OS - The operating system in use.
43
+ * @property {string} Arch - The architecture of the system.
44
+ */
45
+
46
+ /**
47
+ * @function
48
+ * Retrieves environment details.
49
+ * @returns {Promise<EnvironmentInfo>} - A promise that resolves to an object containing OS and system architecture.
50
+ */
51
+ export function Environment() {
52
+ return call(environment);
53
+ }
54
+
55
+ export let invoke = null;
56
+ let environmentCache = null;
57
+
58
+ Environment()
59
+ .then(result => {
60
+ environmentCache = result;
61
+ invoke = IsWindows() ? window.chrome.webview.postMessage : window.webkit.messageHandlers.external.postMessage;
62
+ })
63
+ .catch(error => {
64
+ console.error(`Error getting Environment: ${error}`);
65
+ });
66
+
67
+ /**
68
+ * Checks if the current operating system is Windows.
69
+ *
70
+ * @return {boolean} True if the operating system is Windows, otherwise false.
71
+ */
72
+ export function IsWindows() {
73
+ return environmentCache.OS === "windows";
74
+ }
75
+
76
+ /**
77
+ * Checks if the current operating system is Linux.
78
+ *
79
+ * @returns {boolean} Returns true if the current operating system is Linux, false otherwise.
80
+ */
81
+ export function IsLinux() {
82
+ return environmentCache.OS === "linux";
83
+ }
84
+
85
+ /**
86
+ * Checks if the current environment is a macOS operating system.
87
+ *
88
+ * @returns {boolean} True if the environment is macOS, false otherwise.
89
+ */
90
+ export function IsMac() {
91
+ return environmentCache.OS === "darwin";
92
+ }
93
+
94
+ /**
95
+ * Checks if the current environment architecture is AMD64.
96
+ * @returns {boolean} True if the current environment architecture is AMD64, false otherwise.
97
+ */
98
+ export function IsAMD64() {
99
+ return environmentCache.Arch === "amd64";
100
+ }
101
+
102
+ /**
103
+ * Checks if the current architecture is ARM.
104
+ *
105
+ * @returns {boolean} True if the current architecture is ARM, false otherwise.
106
+ */
107
+ export function IsARM() {
108
+ return environmentCache.Arch === "arm";
109
+ }
110
+
111
+ /**
112
+ * Checks if the current environment is ARM64 architecture.
113
+ *
114
+ * @returns {boolean} - Returns true if the environment is ARM64 architecture, otherwise returns false.
115
+ */
116
+ export function IsARM64() {
117
+ return environmentCache.Arch === "arm64";
118
+ }
package/types.d.ts ADDED
@@ -0,0 +1,130 @@
1
+
2
+ export interface Button {
3
+ // The label of the button
4
+ Label?: string;
5
+ // True if this button is the cancel button (selected when pressing escape)
6
+ IsCancel?: boolean;
7
+ // True if this button is the default button (selected when pressing enter)
8
+ IsDefault?: boolean;
9
+ }
10
+
11
+ interface MessageDialogOptions {
12
+ // The title for the dialog
13
+ Title?: string;
14
+ // The message to display
15
+ Message?: string;
16
+ // The buttons to use on the dialog
17
+ Buttons?: Button[];
18
+ // Whether the dialog is detached from the current window
19
+ Detached?: boolean;
20
+ }
21
+
22
+ export interface OpenFileDialogOptions {
23
+ // Allows the user to be able to select directories
24
+ CanChooseDirectories?: boolean;
25
+ // Allows the user to be able to select files
26
+ CanChooseFiles?: boolean;
27
+ // Provide an option to create directories in the dialog
28
+ CanCreateDirectories?: boolean;
29
+ // Makes the dialog show hidden files
30
+ ShowHiddenFiles?: boolean;
31
+ // Whether the dialog should follow filesystem aliases
32
+ ResolvesAliases?: boolean;
33
+ // Allow the user to select multiple files or directories
34
+ AllowsMultipleSelection?: boolean;
35
+ // Hide the extension when showing the filename
36
+ HideExtension?: boolean;
37
+ // Allow the user to select files where the system hides their extensions
38
+ CanSelectHiddenExtension?: boolean;
39
+ // Treats file packages as directories, e.g. .app on macOS
40
+ TreatsFilePackagesAsDirectories?: boolean;
41
+ // Allows selection of filetypes not specified in the filters
42
+ AllowsOtherFiletypes?: boolean;
43
+ // The file filters to use in the dialog
44
+ Filters?: FileFilter[];
45
+ // The title of the dialog
46
+ Title?: string;
47
+ // The message to display
48
+ Message?: string;
49
+ // The label for the select button
50
+ ButtonText?: string;
51
+ // The default directory to open the dialog in
52
+ Directory?: string;
53
+ // Whether the dialog is detached from the current window
54
+ Detached?: boolean;
55
+ }
56
+ export interface FileFilter {
57
+ // The display name for the filter, e.g. "Text Files"
58
+ DisplayName?: string;
59
+ // The pattern to use for the filter, e.g. "*.txt;*.md"
60
+ Pattern?: string;
61
+ }
62
+ export interface SaveFileDialogOptions {
63
+ // Provide an option to create directories in the dialog
64
+ CanCreateDirectories?: boolean;
65
+ // Makes the dialog show hidden files
66
+ ShowHiddenFiles?: boolean;
67
+ // Allow the user to select files where the system hides their extensions
68
+ CanSelectHiddenExtension?: boolean;
69
+ // Allows selection of filetypes not specified in the filters
70
+ AllowOtherFiletypes?: boolean;
71
+ // Hide the extension when showing the filename
72
+ HideExtension?: boolean;
73
+ // Treats file packages as directories, e.g. .app on macOS
74
+ TreatsFilePackagesAsDirectories?: boolean;
75
+ // The message to show in the dialog
76
+ Message?: string;
77
+ // The default directory to open the dialog in
78
+ Directory?: string;
79
+ // The default filename to use in the dialog
80
+ Filename?: string;
81
+ // The label for the select button
82
+ ButtonText?: string;
83
+ // Whether the dialog is detached from the current window
84
+ Detached?: boolean;
85
+ }
86
+
87
+ export interface Screen {
88
+ // The screen ID
89
+ Id: string;
90
+ // The screen name
91
+ Name: string;
92
+ // The screen scale. 1 = standard resolution, 2: 2x retina, etc.
93
+ Scale: number;
94
+ // The X position of the screen
95
+ X: number;
96
+ // The Y position of the screen
97
+ Y: number;
98
+ // The width and height of the screen
99
+ Size: Size;
100
+ // The bounds of the screen
101
+ Bounds: Rect;
102
+ // The work area of the screen
103
+ WorkArea: Rect;
104
+ // True if this is the primary screen
105
+ IsPrimary: boolean;
106
+ // The rotation of the screen
107
+ Rotation: number;
108
+ }
109
+ export interface Rect {
110
+ X: number;
111
+ Y: number;
112
+ Width: number;
113
+ Height: number;
114
+ }
115
+
116
+ export interface WailsEvent {
117
+ // The name of the event
118
+ Name: string;
119
+ // The data associated with the event
120
+ Data?: any;
121
+ }
122
+
123
+ export interface Size {
124
+ Width: number;
125
+ Height: number;
126
+ }
127
+ export interface Position {
128
+ X: number;
129
+ Y: number;
130
+ }