mirror of
https://github.com/wailsapp/wails.git
synced 2025-05-03 01:30:32 +08:00
Move bridge to Svelte build. Initial support for trays in dev mode
This commit is contained in:
parent
9b9bcd657f
commit
21c07497d7
@ -1 +1 @@
|
|||||||
bridge.js
|
index.js
|
@ -140,11 +140,11 @@ func (b BridgeClient) SetApplicationMenu(menuJSON string) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (b BridgeClient) SetTrayMenu(trayMenuJSON string) {
|
func (b BridgeClient) SetTrayMenu(trayMenuJSON string) {
|
||||||
b.session.log.Info("SetTrayMenu unsupported in Bridge mode")
|
b.session.sendMessage("TS" + trayMenuJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BridgeClient) UpdateTrayMenuLabel(JSON string) {
|
func (b BridgeClient) UpdateTrayMenuLabel(trayMenuJSON string) {
|
||||||
b.session.log.Info("UpdateTrayMenuLabel unsupported in Bridge mode")
|
b.session.sendMessage("TS" + trayMenuJSON)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (b BridgeClient) UpdateContextMenu(contextMenuJSON string) {
|
func (b BridgeClient) UpdateContextMenu(contextMenuJSON string) {
|
1
v2/internal/runtime/js/runtime/.npmignore
Normal file
1
v2/internal/runtime/js/runtime/.npmignore
Normal file
@ -0,0 +1 @@
|
|||||||
|
src
|
@ -1,239 +0,0 @@
|
|||||||
/*
|
|
||||||
_ __ _ __
|
|
||||||
| | / /___ _(_) /____
|
|
||||||
| | /| / / __ `/ / / ___/
|
|
||||||
| |/ |/ / /_/ / / (__ )
|
|
||||||
|__/|__/\__,_/_/_/____/
|
|
||||||
The lightweight framework for web-like apps
|
|
||||||
(c) Lea Anthony 2019-present
|
|
||||||
*/
|
|
||||||
/* jshint esversion: 6 */
|
|
||||||
|
|
||||||
function init() {
|
|
||||||
|
|
||||||
// Bridge object
|
|
||||||
window.wailsbridge = {
|
|
||||||
reconnectOverlay: null,
|
|
||||||
reconnectTimer: 300,
|
|
||||||
wsURL: 'ws://' + window.location.hostname + ':34115/bridge',
|
|
||||||
connectionState: null,
|
|
||||||
config: {},
|
|
||||||
websocket: null,
|
|
||||||
callback: null,
|
|
||||||
overlayHTML:
|
|
||||||
'<div class="wails-reconnect-overlay"><div class="wails-reconnect-overlay-content"><div class="wails-reconnect-overlay-loadingspinner"></div></div></div>',
|
|
||||||
overlayCSS:
|
|
||||||
'.wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;backdrop-filter: blur(20px) saturate(160%) contrast(45%) brightness(140%);display:none;z-index:999999}.wails-reconnect-overlay-content{position:relative;top:50%;transform:translateY(-50%);margin: 0;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAflBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAABAQEEBAQAAAAAAAAEBAQAAAADAwMAAAABAQEAAAAAAAAAAAAAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWCC3waAAAAKXRSTlMALgUMIBk0+xEqJs70Xhb3lu3EjX2EZTlv5eHXvbarQj3cdmpXSqOeUDwaqNAAAAKCSURBVEjHjZTntqsgEIUPVVCwtxg1vfD+L3hHRe8K6snZf+KKn8OewvzsSSeXLruLnz+KHs0gr6DkT3xsRkU6VVn4Ha/UxLe1Z4y64i847sykPBh/AvQ7ry3eFN70oKrfcBJYvm/tQ1qxP4T3emXPeXAkvodPUvtdjbhk+Ft4c0hslTiXVOzxOJ15NWUblQhRsdu3E1AfCjj3Gdm18zSOsiH8Lk4TB480ksy62fiqNo4OpyU8O21l6+hyRtS6z8r1pHlmle5sR1/WXS6Mq2Nl+YeKt3vr+vdH/q4O68tzXuwkiZmngYb4R8Co1jh0+Ww2UTyWxBvtyxLO7QVjO3YOD/lWZpbXDGellFG2Mws58mMnjVZSn7p+XvZ6IF4nn02OJZV0aTO22arp/DgLPtrgpVoi6TPbZm4XQBjY159w02uO0BDdYsfrOEi0M2ulRXlCIPAOuN1NOVhi+riBR3dgwQplYsZRZJLXq23Mlo5njkbY0rZFu3oiNIYG2kqsbVz67OlNuZZIOlfxHDl0UpyRX86z/OYC/3qf1A1xTrMp/PWWM4ePzf8DDp1nesQRpcFk7BlwdzN08ZIALJpCaciQXO0f6k4dnuT/Ewg4l7qSTNzm2SykdHn6GJ12mWc6aCNj/g1cTXpB8YFfr0uVc96aFkkqiIiX4nO+salKwGtIkvfB+Ja8DxMeD3hIXP5mTOYPB4eVT0+32I5ykvPZjesnkGgIREgYnmLrPb0PdV3hoLup2TjcGBPM4mgsfF5BrawZR4/GpzYQzQfrUZCf0TCWYo2DqhdhTJBQ6j4xqmmLN5LjdRIY8LWExiFUsSrza/nmFBqw3I9tEZB9h0lIQSO9if8DkISDAj8CDawAAAAASUVORK5CYII=);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#f00 #eee0 #f00 #eee0;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg); opacity}}',
|
|
||||||
log: function (message) {
|
|
||||||
// eslint-disable-next-line
|
|
||||||
console.log(
|
|
||||||
'%c wails bridge %c ' + message + ' ',
|
|
||||||
'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem',
|
|
||||||
'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem'
|
|
||||||
);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
window.onbeforeunload = function() {
|
|
||||||
if( window.wails.websocket ) {
|
|
||||||
window.wails.websocket.onclose = function () { };
|
|
||||||
window.wails.websocket.close();
|
|
||||||
window.wails.websocket = null;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
function setupIPCBridge() {
|
|
||||||
// darwin
|
|
||||||
window.webkit = {
|
|
||||||
messageHandlers: {
|
|
||||||
external: {
|
|
||||||
postMessage: (message) => {
|
|
||||||
window.wailsbridge.websocket.send(message);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
// Adapted from webview - thanks zserge!
|
|
||||||
function injectCSS(css) {
|
|
||||||
const elem = document.createElement('style');
|
|
||||||
elem.setAttribute('type', 'text/css');
|
|
||||||
elem.appendChild(document.createTextNode(css));
|
|
||||||
const head = document.head || document.getElementsByTagName('head')[0];
|
|
||||||
head.appendChild(elem);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Creates a node in the Dom
|
|
||||||
/**
|
|
||||||
* @param {HTMLElement} parent
|
|
||||||
* @param {string} elementType
|
|
||||||
* @param {string} id
|
|
||||||
* @param {string|null} className
|
|
||||||
* @param {string|null} content
|
|
||||||
*/
|
|
||||||
function createNode(parent, elementType, id, className, content) {
|
|
||||||
const d = document.createElement(elementType);
|
|
||||||
if (id) {
|
|
||||||
d.id = id;
|
|
||||||
}
|
|
||||||
if (className) {
|
|
||||||
d.className = className;
|
|
||||||
}
|
|
||||||
if (content) {
|
|
||||||
d.innerHTML = content;
|
|
||||||
}
|
|
||||||
parent.appendChild(d);
|
|
||||||
return d;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Sets up the overlay
|
|
||||||
function setupOverlay() {
|
|
||||||
const body = document.body;
|
|
||||||
const wailsBridgeNode = createNode(body, 'div', 'wails-bridge', null, null);
|
|
||||||
wailsBridgeNode.innerHTML = window.wailsbridge.overlayHTML;
|
|
||||||
|
|
||||||
// Inject the overlay CSS
|
|
||||||
injectCSS(window.wailsbridge.overlayCSS);
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start the Wails Bridge
|
|
||||||
function startBridge() {
|
|
||||||
// Setup the overlay
|
|
||||||
setupOverlay();
|
|
||||||
|
|
||||||
window.wailsbridge.websocket = null;
|
|
||||||
window.wailsbridge.connectTimer = null;
|
|
||||||
window.wailsbridge.reconnectOverlay = document.querySelector(
|
|
||||||
'.wails-reconnect-overlay'
|
|
||||||
);
|
|
||||||
window.wailsbridge.connectionState = 'disconnected';
|
|
||||||
|
|
||||||
// Shows the overlay
|
|
||||||
function showReconnectOverlay() {
|
|
||||||
window.wailsbridge.reconnectOverlay.style.display = 'block';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Hides the overlay
|
|
||||||
const hideReconnectOverlay = function () {
|
|
||||||
window.wailsbridge.reconnectOverlay.style.display = 'none';
|
|
||||||
}
|
|
||||||
window.wailsbridge.hideReconnectOverlay = hideReconnectOverlay;
|
|
||||||
|
|
||||||
// Adds a script to the Dom.
|
|
||||||
// Removes it if second parameter is true.
|
|
||||||
function addScript(script, remove) {
|
|
||||||
const s = document.createElement('script');
|
|
||||||
s.setAttribute('type', 'text/javascript');
|
|
||||||
s.textContent = script;
|
|
||||||
document.head.appendChild(s);
|
|
||||||
|
|
||||||
// Remove internal messages from the DOM
|
|
||||||
if (remove) {
|
|
||||||
s.parentNode.removeChild(s);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles incoming websocket connections
|
|
||||||
function handleConnect() {
|
|
||||||
window.wailsbridge.log('Connected to backend');
|
|
||||||
setupIPCBridge();
|
|
||||||
hideReconnectOverlay();
|
|
||||||
clearInterval(window.wailsbridge.connectTimer);
|
|
||||||
window.wailsbridge.websocket.onclose = handleDisconnect;
|
|
||||||
window.wailsbridge.websocket.onmessage = handleMessage;
|
|
||||||
window.wailsbridge.connectionState = 'connected';
|
|
||||||
}
|
|
||||||
|
|
||||||
// Handles websocket disconnects
|
|
||||||
function handleDisconnect() {
|
|
||||||
window.wailsbridge.log('Disconnected from backend');
|
|
||||||
window.wailsbridge.websocket = null;
|
|
||||||
window.wailsbridge.connectionState = 'disconnected';
|
|
||||||
showReconnectOverlay();
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Try to connect to the backend every 1s (default value).
|
|
||||||
// Change this value in the main wailsbridge object.
|
|
||||||
function connect() {
|
|
||||||
window.wailsbridge.connectTimer = setInterval(function () {
|
|
||||||
if (window.wailsbridge.websocket == null) {
|
|
||||||
window.wailsbridge.websocket = new WebSocket(window.wailsbridge.wsURL);
|
|
||||||
window.wailsbridge.websocket.onopen = handleConnect;
|
|
||||||
window.wailsbridge.websocket.onerror = function (e) {
|
|
||||||
e.stopImmediatePropagation();
|
|
||||||
e.stopPropagation();
|
|
||||||
e.preventDefault();
|
|
||||||
window.wailsbridge.websocket = null;
|
|
||||||
return false;
|
|
||||||
};
|
|
||||||
}
|
|
||||||
}, window.wailsbridge.reconnectTimer);
|
|
||||||
}
|
|
||||||
|
|
||||||
function handleMessage(message) {
|
|
||||||
// As a bridge we ignore js and css injections
|
|
||||||
switch (message.data[0]) {
|
|
||||||
// Wails library - inject!
|
|
||||||
case 'b':
|
|
||||||
message = message.data.slice(1)
|
|
||||||
addScript(message);
|
|
||||||
window.wailsbridge.log('Loaded Wails Runtime');
|
|
||||||
|
|
||||||
// We need to now send a message to the backend telling it
|
|
||||||
// we have loaded (System Start)
|
|
||||||
window.webkit.messageHandlers.external.postMessage("SS");
|
|
||||||
|
|
||||||
// Now wails runtime is loaded, wails for the ready event
|
|
||||||
// and callback to the main app
|
|
||||||
// window.wails.Events.On('wails:loaded', function () {
|
|
||||||
if (window.wailsbridge.callback) {
|
|
||||||
window.wailsbridge.log('Notifying application');
|
|
||||||
window.wailsbridge.callback(window.wails);
|
|
||||||
}
|
|
||||||
// });
|
|
||||||
break;
|
|
||||||
// // Notifications
|
|
||||||
// case 'n':
|
|
||||||
// addScript(message.data.slice(1), true);
|
|
||||||
// break;
|
|
||||||
// // Binding
|
|
||||||
// case 'b':
|
|
||||||
// const binding = message.data.slice(1);
|
|
||||||
// //log("Binding: " + binding)
|
|
||||||
// window.wails._.NewBinding(binding);
|
|
||||||
// break;
|
|
||||||
// // Call back
|
|
||||||
case 'c':
|
|
||||||
const callbackData = message.data.slice(1);
|
|
||||||
window.wails._.Callback(callbackData);
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
window.wailsbridge.log('Unknown message: ' + message.data);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Start by showing the overlay...
|
|
||||||
showReconnectOverlay();
|
|
||||||
|
|
||||||
// ...and attempt to connect
|
|
||||||
connect();
|
|
||||||
}
|
|
||||||
|
|
||||||
function InitBridge(callback) {
|
|
||||||
// Set up the bridge
|
|
||||||
init();
|
|
||||||
|
|
||||||
// Save the callback
|
|
||||||
window.wailsbridge.callback = callback;
|
|
||||||
|
|
||||||
// Start Bridge
|
|
||||||
startBridge();
|
|
||||||
}
|
|
||||||
|
|
||||||
module.exports = {
|
|
||||||
InitBridge: InitBridge,
|
|
||||||
}
|
|
@ -9,7 +9,7 @@ The lightweight framework for web-like apps
|
|||||||
*/
|
*/
|
||||||
/* jshint esversion: 6 */
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
import { InitBridge } from './bridge';
|
import bridge from './bridge';
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* ready will execute the callback when Wails has loaded
|
* ready will execute the callback when Wails has loaded
|
||||||
@ -25,7 +25,7 @@ function ready(callback) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// If not we need to setup the bridge
|
// If not we need to setup the bridge
|
||||||
InitBridge(callback);
|
bridge.InitBridge(callback);
|
||||||
}
|
}
|
||||||
|
|
||||||
module.exports = {
|
module.exports = {
|
||||||
|
18
v2/internal/runtime/js/runtime/src/Menu.svelte
Normal file
18
v2/internal/runtime/js/runtime/src/Menu.svelte
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
export let menu;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<div class="menu">
|
||||||
|
{#each menu.Menu.Items as menuItem}
|
||||||
|
{#if menuItem.Image.length > 0}
|
||||||
|
<img alt="" src="data:image/png;base64,{menuItem.Image}"/>
|
||||||
|
{/if}
|
||||||
|
<span class="menuitem">{menuItem.Label}</span>
|
||||||
|
{/each}
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
</style>
|
37
v2/internal/runtime/js/runtime/src/Menubar.svelte
Normal file
37
v2/internal/runtime/js/runtime/src/Menubar.svelte
Normal file
@ -0,0 +1,37 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
import {menuVisible} from './store'
|
||||||
|
import {fade} from 'svelte/transition';
|
||||||
|
|
||||||
|
import {trays} from './store'
|
||||||
|
import TrayMenu from "./TrayMenu.svelte";
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $menuVisible }
|
||||||
|
<div class="wails-menubar" transition:fade>
|
||||||
|
<span class="tray-menus">
|
||||||
|
{#each $trays as tray}
|
||||||
|
<TrayMenu {tray}></TrayMenu>
|
||||||
|
{/each}
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tray-menus {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: row;
|
||||||
|
justify-content: flex-end;
|
||||||
|
}
|
||||||
|
.wails-menubar { position: relative;
|
||||||
|
display: block;
|
||||||
|
top: 0;
|
||||||
|
height: 2rem;
|
||||||
|
width: 100%;
|
||||||
|
border-bottom: 1px solid #b3b3b3;
|
||||||
|
box-shadow: antiquewhite;
|
||||||
|
box-shadow: 0px 0px 10px 0px #33333360;
|
||||||
|
}
|
||||||
|
</style>
|
55
v2/internal/runtime/js/runtime/src/Overlay.svelte
Normal file
55
v2/internal/runtime/js/runtime/src/Overlay.svelte
Normal file
@ -0,0 +1,55 @@
|
|||||||
|
<script>
|
||||||
|
|
||||||
|
import { overlayVisible } from './store'
|
||||||
|
import { fade, } from 'svelte/transition';
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
{#if $overlayVisible }
|
||||||
|
<div class="wails-reconnect-overlay" transition:fade="{{ duration: 200 }}">
|
||||||
|
<div class="wails-reconnect-overlay-content">
|
||||||
|
<div class="wails-reconnect-overlay-loadingspinner"></div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
{/if}
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.wails-reconnect-overlay {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
backdrop-filter: blur(20px) saturate(160%) contrast(45%) brightness(140%);
|
||||||
|
z-index: 999999
|
||||||
|
}
|
||||||
|
|
||||||
|
.wails-reconnect-overlay-content {
|
||||||
|
position: relative;
|
||||||
|
top: 50%;
|
||||||
|
transform: translateY(-50%);
|
||||||
|
margin: 0;
|
||||||
|
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAflBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAAAAABAQEEBAQAAAAAAAAEBAQAAAADAwMAAAABAQEAAAAAAAAAAAAAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWCC3waAAAAKXRSTlMALgUMIBk0+xEqJs70Xhb3lu3EjX2EZTlv5eHXvbarQj3cdmpXSqOeUDwaqNAAAAKCSURBVEjHjZTntqsgEIUPVVCwtxg1vfD+L3hHRe8K6snZf+KKn8OewvzsSSeXLruLnz+KHs0gr6DkT3xsRkU6VVn4Ha/UxLe1Z4y64i847sykPBh/AvQ7ry3eFN70oKrfcBJYvm/tQ1qxP4T3emXPeXAkvodPUvtdjbhk+Ft4c0hslTiXVOzxOJ15NWUblQhRsdu3E1AfCjj3Gdm18zSOsiH8Lk4TB480ksy62fiqNo4OpyU8O21l6+hyRtS6z8r1pHlmle5sR1/WXS6Mq2Nl+YeKt3vr+vdH/q4O68tzXuwkiZmngYb4R8Co1jh0+Ww2UTyWxBvtyxLO7QVjO3YOD/lWZpbXDGellFG2Mws58mMnjVZSn7p+XvZ6IF4nn02OJZV0aTO22arp/DgLPtrgpVoi6TPbZm4XQBjY159w02uO0BDdYsfrOEi0M2ulRXlCIPAOuN1NOVhi+riBR3dgwQplYsZRZJLXq23Mlo5njkbY0rZFu3oiNIYG2kqsbVz67OlNuZZIOlfxHDl0UpyRX86z/OYC/3qf1A1xTrMp/PWWM4ePzf8DDp1nesQRpcFk7BlwdzN08ZIALJpCaciQXO0f6k4dnuT/Ewg4l7qSTNzm2SykdHn6GJ12mWc6aCNj/g1cTXpB8YFfr0uVc96aFkkqiIiX4nO+salKwGtIkvfB+Ja8DxMeD3hIXP5mTOYPB4eVT0+32I5ykvPZjesnkGgIREgYnmLrPb0PdV3hoLup2TjcGBPM4mgsfF5BrawZR4/GpzYQzQfrUZCf0TCWYo2DqhdhTJBQ6j4xqmmLN5LjdRIY8LWExiFUsSrza/nmFBqw3I9tEZB9h0lIQSO9if8DkISDAj8CDawAAAAASUVORK5CYII=);
|
||||||
|
background-repeat: no-repeat;
|
||||||
|
background-position: center
|
||||||
|
}
|
||||||
|
|
||||||
|
.wails-reconnect-overlay-loadingspinner {
|
||||||
|
pointer-events: none;
|
||||||
|
width: 2.5em;
|
||||||
|
height: 2.5em;
|
||||||
|
border: .4em solid transparent;
|
||||||
|
border-color: #f00 #eee0 #f00 #eee0;
|
||||||
|
border-radius: 50%;
|
||||||
|
animation: loadingspin 1s linear infinite;
|
||||||
|
margin: auto;
|
||||||
|
padding: 2.5em
|
||||||
|
}
|
||||||
|
|
||||||
|
@keyframes loadingspin {
|
||||||
|
100% {
|
||||||
|
transform: rotate(360deg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
</style>
|
21
v2/internal/runtime/js/runtime/src/TrayMenu.svelte
Normal file
21
v2/internal/runtime/js/runtime/src/TrayMenu.svelte
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
<script>
|
||||||
|
import Menu from "./Menu.svelte";
|
||||||
|
|
||||||
|
export let tray;
|
||||||
|
|
||||||
|
</script>
|
||||||
|
|
||||||
|
<span class="tray-menu">
|
||||||
|
<span class="label">{tray.Label}</span>
|
||||||
|
<!-- <Menu menu="{tray.ProcessedMenu}"/>-->
|
||||||
|
</span>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
|
||||||
|
.tray-menu {
|
||||||
|
padding-left: 0.5rem;
|
||||||
|
padding-right: 0.5rem;
|
||||||
|
overflow: visible;
|
||||||
|
font-size: 14px;
|
||||||
|
}
|
||||||
|
</style>
|
45
v2/internal/runtime/js/runtime/src/main.js
Normal file
45
v2/internal/runtime/js/runtime/src/main.js
Normal file
@ -0,0 +1,45 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
import Overlay from './Overlay.svelte';
|
||||||
|
import MenuBar from './Menubar.svelte';
|
||||||
|
import {showOverlay} from "./store";
|
||||||
|
import {StartWebsocket} from "./websocket";
|
||||||
|
|
||||||
|
let components = {};
|
||||||
|
|
||||||
|
function setupMenuBar() {
|
||||||
|
components.menubar = new MenuBar({
|
||||||
|
target: document.body,
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sets up the overlay
|
||||||
|
function setupOverlay() {
|
||||||
|
components.overlay = new Overlay({
|
||||||
|
target: document.body,
|
||||||
|
anchor: document.querySelector('#wails-bridge'),
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
export function InitBridge(callback) {
|
||||||
|
|
||||||
|
setupMenuBar()
|
||||||
|
|
||||||
|
// Setup the overlay
|
||||||
|
setupOverlay();
|
||||||
|
|
||||||
|
// Start by showing the overlay...
|
||||||
|
showOverlay();
|
||||||
|
|
||||||
|
// ...and attempt to connect
|
||||||
|
StartWebsocket(callback);
|
||||||
|
}
|
35
v2/internal/runtime/js/runtime/src/rollup.config.js
Normal file
35
v2/internal/runtime/js/runtime/src/rollup.config.js
Normal file
@ -0,0 +1,35 @@
|
|||||||
|
import resolve from '@rollup/plugin-node-resolve';
|
||||||
|
// import commonjs from '@rollup/plugin-commonjs';
|
||||||
|
import svelte from 'rollup-plugin-svelte';
|
||||||
|
|
||||||
|
export default [
|
||||||
|
// browser-friendly UMD build
|
||||||
|
{
|
||||||
|
input: 'main.js',
|
||||||
|
output: {
|
||||||
|
name: 'bridge',
|
||||||
|
file: '../bridge.js',
|
||||||
|
format: 'umd',
|
||||||
|
exports: "named"
|
||||||
|
},
|
||||||
|
plugins: [
|
||||||
|
svelte({
|
||||||
|
// Optionally, preprocess components with svelte.preprocess:
|
||||||
|
// https://svelte.dev/docs#svelte_preprocess
|
||||||
|
// preprocess: {
|
||||||
|
// style: ({content}) => {
|
||||||
|
// return transformStyles(content);
|
||||||
|
// }
|
||||||
|
// },
|
||||||
|
|
||||||
|
// Emit CSS as "files" for other plugins to process. default is true
|
||||||
|
emitCss: false,
|
||||||
|
|
||||||
|
}),
|
||||||
|
resolve({browser: true}), // so Rollup can find `ms`
|
||||||
|
// commonjs() // so Rollup can convert `ms` to an ES module
|
||||||
|
]
|
||||||
|
},
|
||||||
|
|
||||||
|
|
||||||
|
];
|
39
v2/internal/runtime/js/runtime/src/store.js
Normal file
39
v2/internal/runtime/js/runtime/src/store.js
Normal file
@ -0,0 +1,39 @@
|
|||||||
|
|
||||||
|
import { writable } from 'svelte/store';
|
||||||
|
|
||||||
|
/** Overlay */
|
||||||
|
export const overlayVisible = writable(false);
|
||||||
|
|
||||||
|
export function showOverlay() {
|
||||||
|
overlayVisible.set(true);
|
||||||
|
}
|
||||||
|
export function hideOverlay() {
|
||||||
|
overlayVisible.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Menubar **/
|
||||||
|
export const menuVisible = writable(true);
|
||||||
|
|
||||||
|
export function showMenuBar() {
|
||||||
|
menuVisible.set(true);
|
||||||
|
}
|
||||||
|
export function hideMenuBar() {
|
||||||
|
menuVisible.set(false);
|
||||||
|
}
|
||||||
|
|
||||||
|
/** Trays **/
|
||||||
|
|
||||||
|
export const trays = writable([]);
|
||||||
|
export function setTray(tray) {
|
||||||
|
trays.update((current) => {
|
||||||
|
// Remove existing if it exists, else add
|
||||||
|
const index = current.findIndex(item => item.ID === tray.ID);
|
||||||
|
if ( index === -1 ) {
|
||||||
|
current.push(tray);
|
||||||
|
} else {
|
||||||
|
current[index] = tray;
|
||||||
|
}
|
||||||
|
return current;
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
162
v2/internal/runtime/js/runtime/src/websocket.js
Normal file
162
v2/internal/runtime/js/runtime/src/websocket.js
Normal file
@ -0,0 +1,162 @@
|
|||||||
|
/*
|
||||||
|
_ __ _ __
|
||||||
|
| | / /___ _(_) /____
|
||||||
|
| | /| / / __ `/ / / ___/
|
||||||
|
| |/ |/ / /_/ / / (__ )
|
||||||
|
|__/|__/\__,_/_/_/____/
|
||||||
|
The lightweight framework for web-like apps
|
||||||
|
(c) Lea Anthony 2019-present
|
||||||
|
*/
|
||||||
|
/* jshint esversion: 6 */
|
||||||
|
|
||||||
|
|
||||||
|
import {setTray, hideOverlay, showOverlay} from "./store";
|
||||||
|
|
||||||
|
let websocket = null;
|
||||||
|
let callback = null;
|
||||||
|
let connectTimer;
|
||||||
|
|
||||||
|
function log(message) {
|
||||||
|
// eslint-disable-next-line
|
||||||
|
console.log(
|
||||||
|
'%c wails bridge %c ' + message + ' ',
|
||||||
|
'background: #aa0000; color: #fff; border-radius: 3px 0px 0px 3px; padding: 1px; font-size: 0.7rem',
|
||||||
|
'background: #009900; color: #fff; border-radius: 0px 3px 3px 0px; padding: 1px; font-size: 0.7rem'
|
||||||
|
);
|
||||||
|
}
|
||||||
|
|
||||||
|
export function StartWebsocket(userCallback) {
|
||||||
|
|
||||||
|
callback = userCallback;
|
||||||
|
|
||||||
|
window.onbeforeunload = function() {
|
||||||
|
if( websocket ) {
|
||||||
|
websocket.onclose = function () { };
|
||||||
|
websocket.close();
|
||||||
|
websocket = null;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// ...and attempt to connect
|
||||||
|
connect();
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
function setupIPCBridge() {
|
||||||
|
// darwin
|
||||||
|
window.webkit = {
|
||||||
|
messageHandlers: {
|
||||||
|
external: {
|
||||||
|
postMessage: (message) => {
|
||||||
|
websocket.send(message);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles incoming websocket connections
|
||||||
|
function handleConnect() {
|
||||||
|
log('Connected to backend');
|
||||||
|
setupIPCBridge();
|
||||||
|
hideOverlay();
|
||||||
|
clearInterval(connectTimer);
|
||||||
|
websocket.onclose = handleDisconnect;
|
||||||
|
websocket.onmessage = handleMessage;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Handles websocket disconnects
|
||||||
|
function handleDisconnect() {
|
||||||
|
log('Disconnected from backend');
|
||||||
|
websocket = null;
|
||||||
|
showOverlay();
|
||||||
|
connect();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Try to connect to the backend every 1s (default value).
|
||||||
|
function connect() {
|
||||||
|
connectTimer = setInterval(function () {
|
||||||
|
if (websocket == null) {
|
||||||
|
websocket = new WebSocket('ws://' + window.location.hostname + ':34115/bridge');
|
||||||
|
websocket.onopen = handleConnect;
|
||||||
|
websocket.onerror = function (e) {
|
||||||
|
e.stopImmediatePropagation();
|
||||||
|
e.stopPropagation();
|
||||||
|
e.preventDefault();
|
||||||
|
websocket = null;
|
||||||
|
return false;
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}, 1000);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Adds a script to the Dom.
|
||||||
|
// Removes it if second parameter is true.
|
||||||
|
function addScript(script, remove) {
|
||||||
|
const s = document.createElement('script');
|
||||||
|
s.setAttribute('type', 'text/javascript');
|
||||||
|
s.textContent = script;
|
||||||
|
document.head.appendChild(s);
|
||||||
|
|
||||||
|
// Remove internal messages from the DOM
|
||||||
|
if (remove) {
|
||||||
|
s.parentNode.removeChild(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
function handleMessage(message) {
|
||||||
|
// As a bridge we ignore js and css injections
|
||||||
|
switch (message.data[0]) {
|
||||||
|
// Wails library - inject!
|
||||||
|
case 'b':
|
||||||
|
message = message.data.slice(1)
|
||||||
|
addScript(message);
|
||||||
|
log('Loaded Wails Runtime');
|
||||||
|
|
||||||
|
// We need to now send a message to the backend telling it
|
||||||
|
// we have loaded (System Start)
|
||||||
|
window.webkit.messageHandlers.external.postMessage("SS");
|
||||||
|
|
||||||
|
// Now wails runtime is loaded, wails for the ready event
|
||||||
|
// and callback to the main app
|
||||||
|
// window.wails.Events.On('wails:loaded', function () {
|
||||||
|
if (callback) {
|
||||||
|
log('Notifying application');
|
||||||
|
callback(window.wails);
|
||||||
|
}
|
||||||
|
// });
|
||||||
|
break;
|
||||||
|
// // Notifications
|
||||||
|
// case 'n':
|
||||||
|
// addScript(message.data.slice(1), true);
|
||||||
|
// break;
|
||||||
|
// // Binding
|
||||||
|
// case 'b':
|
||||||
|
// const binding = message.data.slice(1);
|
||||||
|
// //log("Binding: " + binding)
|
||||||
|
// window.wails._.NewBinding(binding);
|
||||||
|
// break;
|
||||||
|
// // Call back
|
||||||
|
case 'c':
|
||||||
|
const callbackData = message.data.slice(1);
|
||||||
|
window.wails._.Callback(callbackData);
|
||||||
|
break;
|
||||||
|
// Tray
|
||||||
|
case 'T':
|
||||||
|
const trayMessage = message.data.slice(1);
|
||||||
|
switch (trayMessage[0]) {
|
||||||
|
case 'S':
|
||||||
|
// Set tray
|
||||||
|
const trayJSON = trayMessage.slice(1);
|
||||||
|
let tray = JSON.parse(trayJSON)
|
||||||
|
setTray(tray)
|
||||||
|
break
|
||||||
|
default:
|
||||||
|
log('Unknown tray message: ' + message.data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
log('Unknown message: ' + message.data);
|
||||||
|
}
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user