mirror of
https://github.com/taigrr/wails.git
synced 2026-04-03 21:52:45 -07:00
Compare commits
34 Commits
Create-con
...
port-to-cu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
b5b78fddee | ||
|
|
c905185467 | ||
|
|
47ca7879cd | ||
|
|
6202b3bf3e | ||
|
|
ea94c2de1f | ||
|
|
eb0d4bc42f | ||
|
|
b323c3db20 | ||
|
|
1670ac6567 | ||
|
|
c941176018 | ||
|
|
a060d9dcc0 | ||
|
|
ba208dce44 | ||
|
|
9bbac46b3f | ||
|
|
d8c591e64c | ||
|
|
2c28a8f550 | ||
|
|
d6c5586159 | ||
|
|
08a7893b1d | ||
|
|
fa6cf17079 | ||
|
|
fe2a20f92a | ||
|
|
b713d57168 | ||
|
|
17ca06693e | ||
|
|
243d738d64 | ||
|
|
3f50b95f26 | ||
|
|
f0d8ce99a1 | ||
|
|
259eec97d6 | ||
|
|
8b2168abe7 | ||
|
|
a51e127309 | ||
|
|
c5cee79ff7 | ||
|
|
9393b08c3f | ||
|
|
0ca039e914 | ||
|
|
cd8b4f088f | ||
|
|
847842504b | ||
|
|
8ab91d31fe | ||
|
|
bb4d891549 | ||
|
|
529e4cc07e |
File diff suppressed because one or more lines are too long
17
app.go
17
app.go
@@ -2,13 +2,12 @@ package wails
|
||||
|
||||
import (
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
"github.com/wailsapp/wails/cmd/frameworks"
|
||||
)
|
||||
|
||||
// -------------------------------- Compile time Flags ------------------------------
|
||||
|
||||
// DebugMode indicates if we are in debug Mode
|
||||
var DebugMode = "true"
|
||||
// BuildMode indicates what mode we are in
|
||||
var BuildMode = "prod"
|
||||
|
||||
// ----------------------------------------------------------------------------------
|
||||
|
||||
@@ -18,7 +17,6 @@ type App struct {
|
||||
cli *cmd.Cli // In debug mode, we have a cli
|
||||
renderer Renderer // The renderer is what we will render the app to
|
||||
logLevel string // The log level of the app
|
||||
headless bool // Indicates if the app should be started in headless mode
|
||||
ipc *ipcManager // Handles the IPC calls
|
||||
log *CustomLogger // Logger
|
||||
bindingManager *bindingManager // Handles binding of Go code to renderer
|
||||
@@ -55,7 +53,7 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
||||
result.config = appconfig
|
||||
|
||||
// Set up the CLI if not in release mode
|
||||
if DebugMode == "true" {
|
||||
if BuildMode != "prod" {
|
||||
result.cli = result.setupCli()
|
||||
} else {
|
||||
// Disable Inspector in release mode
|
||||
@@ -67,7 +65,7 @@ func CreateApp(optionalConfig ...*AppConfig) *App {
|
||||
|
||||
// Run the app
|
||||
func (a *App) Run() error {
|
||||
if DebugMode == "true" {
|
||||
if BuildMode != "prod" {
|
||||
return a.cli.Run()
|
||||
}
|
||||
|
||||
@@ -84,7 +82,7 @@ func (a *App) start() error {
|
||||
a.log.Info("Starting")
|
||||
|
||||
// Check if we are to run in headless mode
|
||||
if a.headless {
|
||||
if BuildMode == "bridge" {
|
||||
a.renderer = &Headless{}
|
||||
}
|
||||
|
||||
@@ -109,11 +107,6 @@ func (a *App) start() error {
|
||||
return err
|
||||
}
|
||||
|
||||
// Inject framework, if specified
|
||||
if frameworks.FrameworkToUse != nil {
|
||||
a.renderer.InjectFramework(frameworks.FrameworkToUse.JS, frameworks.FrameworkToUse.CSS)
|
||||
}
|
||||
|
||||
// Inject CSS
|
||||
a.renderer.AddCSSList(a.cssCache)
|
||||
|
||||
|
||||
@@ -15,7 +15,7 @@ func (app *App) setupCli() *cmd.Cli {
|
||||
// Setup cli to handle loglevel and headless flags
|
||||
result.
|
||||
StringFlag("loglevel", "Sets the log level [debug|info|error|panic|fatal]. Default debug", &app.logLevel).
|
||||
BoolFlag("headless", "Runs the app in headless mode", &app.headless).
|
||||
// BoolFlag("headless", "Runs the app in headless mode", &app.headless).
|
||||
Action(app.start)
|
||||
|
||||
// Banner
|
||||
|
||||
@@ -1,214 +0,0 @@
|
||||
/*
|
||||
Wails Bridge (c) 2019-present Lea Anthony
|
||||
|
||||
This library creates a bridge between your application
|
||||
and the frontend, allowing you to develop your app using
|
||||
standard tooling (browser extensions, live reload, etc).
|
||||
|
||||
Usage:
|
||||
```
|
||||
import Bridge from "./wailsbridge";
|
||||
Bridge.Start(startApp);
|
||||
```
|
||||
|
||||
The given callback (startApp in the example) will be called
|
||||
when the bridge has successfully initialised. It passes the
|
||||
window.wails object back, in case it is not accessible directly.
|
||||
*/
|
||||
|
||||
// Bridge object
|
||||
window.wailsbridge = {
|
||||
reconnectOverlay: null,
|
||||
reconnectTimer: 300,
|
||||
wsURL: "ws://localhost: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-title">Wails Bridge</div><br><div class="wails-reconnect-overlay-loadingspinner"></div><br><div id="wails-reconnect-overlay-message">Waiting for backend</div></div></div>',
|
||||
overlayCSS:
|
||||
".wails-reconnect-overlay{position:fixed;top:0;left:0;width:100%;height:100%;background:rgba(0,0,0,.6);font-family:sans-serif;display:none;z-index:999999}.wails-reconnect-overlay-content{padding:20px 30px;text-align:center;width:20em;position:relative;height:14em;border-radius:1em;margin:5% auto 0;background-color:#fff;box-shadow:1px 1px 20px 3px;background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC);background-repeat:no-repeat;background-position:center}.wails-reconnect-overlay-title{font-size:2em}.wails-reconnect-overlay-message{font-size:1.3em}.wails-reconnect-overlay-loadingspinner{pointer-events:none;width:2.5em;height:2.5em;border:.4em solid transparent;border-color:#3E67EC #eee #eee;border-radius:50%;animation:loadingspin 1s linear infinite;margin:auto;padding:2.5em}@keyframes loadingspin{100%{transform:rotate(360deg)}}",
|
||||
log: function (message) {
|
||||
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"
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
// Adapted from webview - thanks zserge!
|
||||
function injectCSS(css) {
|
||||
var elem = document.createElement("style");
|
||||
elem.setAttribute("type", "text/css");
|
||||
if (elem.styleSheet) {
|
||||
elem.styleSheet.cssText = css;
|
||||
} else {
|
||||
elem.appendChild(document.createTextNode(css));
|
||||
}
|
||||
var head = document.head || document.getElementsByTagName("head")[0];
|
||||
head.appendChild(elem);
|
||||
}
|
||||
|
||||
// Creates a node in the Dom
|
||||
function createNode(parent, elementType, id, className, content) {
|
||||
var 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() {
|
||||
var body = document.body;
|
||||
var wailsBridgeNode = createNode(body, "div", "wails-bridge");
|
||||
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
|
||||
function hideReconnectOverlay() {
|
||||
window.wailsbridge.reconnectOverlay.style.display = "none";
|
||||
}
|
||||
|
||||
// Bridge external.invoke
|
||||
window.external = {
|
||||
invoke: function (msg) {
|
||||
window.wailsbridge.websocket.send(msg);
|
||||
}
|
||||
};
|
||||
|
||||
// Adds a script to the Dom.
|
||||
// Removes it if second parameter is true.
|
||||
function addScript(script, remove) {
|
||||
var s = document.createElement("script");
|
||||
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");
|
||||
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 300ms (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 "w":
|
||||
addScript(message.data.slice(1));
|
||||
|
||||
// Now wails runtime is loaded, wails for the ready event
|
||||
// and callback to the main app
|
||||
window.wails.events.on("wails:loaded", function () {
|
||||
window.wailsbridge.log("Wails Ready");
|
||||
if (window.wailsbridge.callback) {
|
||||
window.wailsbridge.log("Notifying application");
|
||||
window.wailsbridge.callback(window.wails);
|
||||
}
|
||||
});
|
||||
window.wailsbridge.log("Loaded Wails Runtime");
|
||||
break;
|
||||
// Notifications
|
||||
case "n":
|
||||
addScript(message.data.slice(1), true);
|
||||
break;
|
||||
// Binding
|
||||
case "b":
|
||||
var binding = message.data.slice(1)
|
||||
//log("Binding: " + binding)
|
||||
window.wails._.newBinding(binding);
|
||||
break;
|
||||
// Call back
|
||||
case "c":
|
||||
var callbackData = message.data.slice(1);
|
||||
log("Callback = " + callbackData);
|
||||
window.wails._.callback(callbackData);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Start by showing the overlay...
|
||||
showReconnectOverlay();
|
||||
|
||||
// ...and attempt to connect
|
||||
connect();
|
||||
}
|
||||
|
||||
export default {
|
||||
// The main function
|
||||
// Passes the main Wails object to the callback if given.
|
||||
Start: function (callback) {
|
||||
// Save the callback
|
||||
window.wailsbridge.callback = callback;
|
||||
|
||||
// Start Bridge
|
||||
startBridge();
|
||||
}
|
||||
};
|
||||
@@ -1,15 +0,0 @@
|
||||
/*
|
||||
Wails Bridge (c) 2019-present Lea Anthony
|
||||
|
||||
This prod version is to get around having to rewrite your code
|
||||
for production. When doing a release build, this file will be used
|
||||
instead of the full version.
|
||||
*/
|
||||
|
||||
export default {
|
||||
// The main function
|
||||
// Passes the main Wails object to the callback if given.
|
||||
Start: function (callback) {
|
||||
return callback();
|
||||
}
|
||||
};
|
||||
2
assets/default/jquery.3.3.1.min.js
vendored
2
assets/default/jquery.3.3.1.min.js
vendored
File diff suppressed because one or more lines are too long
@@ -12,7 +12,8 @@
|
||||
```
|
||||
|
||||
The given callback (startApp in the example) will be called
|
||||
when the bridge has successfully initialised.
|
||||
when the bridge has successfully initialised. It passes the
|
||||
window.wails object back, in case it is not accessible directly.
|
||||
*/
|
||||
|
||||
// Bridge object
|
||||
@@ -169,7 +170,7 @@ function startBridge() {
|
||||
window.wailsbridge.log("Wails Ready");
|
||||
if (window.wailsbridge.callback) {
|
||||
window.wailsbridge.log("Notifying application");
|
||||
window.wailsbridge.callback();
|
||||
window.wailsbridge.callback(window.wails);
|
||||
}
|
||||
});
|
||||
window.wailsbridge.log("Loaded Wails Runtime");
|
||||
@@ -181,13 +182,13 @@ function startBridge() {
|
||||
// Binding
|
||||
case "b":
|
||||
var binding = message.data.slice(1);
|
||||
//window.wailsbridge.log("Binding: " + binding)
|
||||
//log("Binding: " + binding)
|
||||
window.wails._.newBinding(binding);
|
||||
break;
|
||||
// Call back
|
||||
case "c":
|
||||
var callbackData = message.data.slice(1);
|
||||
// window.wailsbridge.log("Callback = " + callbackData);
|
||||
log("Callback = " + callbackData);
|
||||
window.wails._.callback(callbackData);
|
||||
break;
|
||||
}
|
||||
@@ -9,7 +9,9 @@
|
||||
export default {
|
||||
// The main function
|
||||
// Passes the main Wails object to the callback if given.
|
||||
Start: function (callback) {
|
||||
return callback();
|
||||
Start: function(callback) {
|
||||
if (callback) {
|
||||
callback();
|
||||
}
|
||||
}
|
||||
};
|
||||
@@ -1,229 +0,0 @@
|
||||
<html>
|
||||
|
||||
<head>
|
||||
<title>Wails Headless</title>
|
||||
<style>
|
||||
.wails-reconnect-overlay {
|
||||
position: fixed;
|
||||
top: 0;
|
||||
left: 0;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
background: rgba(0, 0, 0, 0.6);
|
||||
font-family: sans-serif;
|
||||
display: none;
|
||||
z-index: 999999;
|
||||
}
|
||||
|
||||
.wails-reconnect-overlay-content {
|
||||
padding: 20px 30px;
|
||||
text-align: center;
|
||||
width: 20em;
|
||||
position: relative;
|
||||
height: 14em;
|
||||
border-radius: 1em;
|
||||
margin: 5% auto 0;
|
||||
background-color: white;
|
||||
box-shadow: 1px 1px 20px 3px;
|
||||
background-image: url("data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAC8AAAAuCAMAAACPpbA7AAAAqFBMVEUAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAEBAQAAAAAAAAEBAQAAAAAAAAAAAAEBAQEBAQDAwMBAQEAAAABAQEAAAAAAAAAAAABAQEAAAAAAAACAgICAgIBAQEAAAAAAAAAAAAAAAAAAAAAAAABAQEAAAACAgIAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAFBQWKCj6oAAAAN3RSTlMALiIqDhkGBAswJjP0GxP6NR4W9/ztjRDMhWU50G9g5eHXvbZ9XEI9xZTcqZl2aldKo55QwoCvZUgzhAAAAs9JREFUSMeNleeWqjAUhU0BCaH3Itiw9zKT93+zG02QK1hm/5HF+jzZJ6fQe6cyXE+jg9X7o9wxuylIIf4Tv2V3+bOrEXnf8dwQ/KQIGDN2/S+4OmVCVXL/ScBnfibxURqIByP/hONE8r8T+bDMlQ98KSl7Y8hzjpS8v1qtDh8u5f8KQpGpfnPPhqG8JeogN37Hq9eaN2xRhIwAaGnvws8F1ShxqK5ob2twYi1FAMD4rXsYtnC/JEiRbl4cUrCWhnMCLRFemXezXbb59QK4WASOsm6n2W1+4CBT2JmtzQ6fsrbGubR/NFbd2g5Y179+5w/GEHaKsHjYCet7CgrXU3txarNC7YxOVJtIj4/ERzMdZfzc31hp+8cD6eGILgarZY9uZ12hAs03vfBD9C171gS5Omz7OcvxALQIn4u8RRBBBcsi9WW2woO9ipLgfzpYlggg3ZRdROUC8KT7QLqq3W9KB5BbdFVg4929kdwp6+qaZnMCCNBdj+NyN1W885Ry/AL3D4AQbsVV4noCiM/C83kyYq80XlDAYQtralOiDzoRAHlotWl8q2tjvYlOgcg1A8jEApZa+C06TBdAz2Qv0wu11I/zZOyJQ6EwGez2P2b8PIQr1hwwnAZsAxwA4UAYOyXUxM/xp6tHAn4GUmPGM9R28oVxgC0e/zQJJI6DyhyZ1r7uzRQhpcW7x7vTaWSzKSG6aep77kroTEl3U81uSVaUTtgEINfC8epx+Q4F9SpplHG84Ek6m4RAq9/TLkOBrxyeuddZhHvGIp1XXfFy3Z3vtwNblKGiDn+J+92vwwABHghj7HnzlS1H5kB49AZvdGCFgiBPq69qfXPr3y++yilF0ON4R8eR7spAsLpZ95NqAW5tab1c4vkZm6aleajchMwYTdILQQTwE2OV411ZM9WztDjPql12caBi6gDpUKmDd4U1XNdQxZ4LIXQ5/Tr4P7I9tYcFrDK3AAAAAElFTkSuQmCC");
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
}
|
||||
|
||||
.wails-reconnect-overlay-title {
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.wails-reconnect-overlay-message {
|
||||
font-size: 1.3em;
|
||||
}
|
||||
|
||||
/* https://codepen.io/EastingAndNorthing/pen/aNWrZz - Cheers Mark! */
|
||||
|
||||
.wails-reconnect-overlay-loadingspinner {
|
||||
pointer-events: none;
|
||||
width: 2.5em;
|
||||
height: 2.5em;
|
||||
border: 0.4em solid transparent;
|
||||
border-color: #eee;
|
||||
border-top-color: #3E67EC;
|
||||
border-radius: 50%;
|
||||
animation: loadingspin 1s linear infinite;
|
||||
margin: auto;
|
||||
padding: 2.5em;
|
||||
}
|
||||
|
||||
@keyframes loadingspin {
|
||||
100% {
|
||||
transform: rotate(360deg)
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
|
||||
<body>
|
||||
<div class="wails-reconnect-overlay">
|
||||
<div class="wails-reconnect-overlay-content">
|
||||
<div class="wails-reconnect-overlay-title">Disconnected</div><br>
|
||||
<div class="wails-reconnect-overlay-loadingspinner"></div><br>
|
||||
<div class="wails-reconnect-overlay-message">Waiting for backend</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div id="app"></div>
|
||||
|
||||
<script id="wails-headless-runtime">
|
||||
(function () {
|
||||
|
||||
var websocket = null;
|
||||
var connectTimer = null;
|
||||
var reconnectOverlay = document.querySelector(".wails-reconnect-overlay");
|
||||
var connectionState = "disconnected";
|
||||
|
||||
function showReconnectOverlay() {
|
||||
reconnectOverlay.style.display = 'block';
|
||||
}
|
||||
|
||||
function hideReconnectOverlay() {
|
||||
reconnectOverlay.style.display = 'none';
|
||||
}
|
||||
|
||||
window.external = {
|
||||
invoke: function (msg) {
|
||||
websocket.send(msg);
|
||||
}
|
||||
};
|
||||
|
||||
// Adds a script to the Dom.
|
||||
// Removes it if second parameter is true.
|
||||
function addScript(script, remove) {
|
||||
var s = document.createElement("script");
|
||||
s.textContent = script;
|
||||
document.head.appendChild(s);
|
||||
|
||||
// Remove internal messages from the DOM
|
||||
if (remove) {
|
||||
s.parentNode.removeChild(s);
|
||||
}
|
||||
}
|
||||
|
||||
// Adapted from webview - thanks zserge!
|
||||
function injectCSS(css) {
|
||||
var elem = document.createElement("style");
|
||||
elem.setAttribute("type", "text/css");
|
||||
if (elem.styleSheet) {
|
||||
elem.styleSheet.cssText = css;
|
||||
} else {
|
||||
elem.appendChild(document.createTextNode(css));
|
||||
}
|
||||
var head = document.head || document.getElementsByTagName("head")[0];
|
||||
head.appendChild(elem);
|
||||
}
|
||||
|
||||
function handleConnect() {
|
||||
log("Connected to backend");
|
||||
hideReconnectOverlay();
|
||||
clearInterval(connectTimer);
|
||||
websocket.onclose = handleDisconnect;
|
||||
websocket.onmessage = handleMessage;
|
||||
connectionState = "connected";
|
||||
// websocket.onerror = function () { }
|
||||
}
|
||||
|
||||
function handleDisconnect() {
|
||||
log("Disconnected from backend");
|
||||
websocket = null;
|
||||
connectionState = "disconnected";
|
||||
showReconnectOverlay();
|
||||
connect();
|
||||
}
|
||||
|
||||
function connect() {
|
||||
connectTimer = setInterval(function () {
|
||||
if (websocket == null) {
|
||||
websocket = new WebSocket("ws://localhost:34115/ws")
|
||||
websocket.onopen = handleConnect;
|
||||
websocket.onerror = function (e) {
|
||||
e.stopImmediatePropagation();
|
||||
e.stopPropagation();
|
||||
e.preventDefault();
|
||||
websocket = null;
|
||||
return false
|
||||
}
|
||||
}
|
||||
}, 300);
|
||||
}
|
||||
function log(message) {
|
||||
console.log(
|
||||
"%c wails headless %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"
|
||||
);
|
||||
}
|
||||
|
||||
function handleMessage(message) {
|
||||
// As a bridge we ignore js and css injections
|
||||
debugger;
|
||||
|
||||
switch (message.data[0]) {
|
||||
// Wails library - inject!
|
||||
case "w":
|
||||
addScript(message.data.slice(1));
|
||||
|
||||
// Now wails runtime is loaded, wails for the ready event
|
||||
// and callback to the main app
|
||||
window.wails.events.on("wails:loaded", function () {
|
||||
log("Wails Ready");
|
||||
});
|
||||
log("Loaded Wails Runtime");
|
||||
break;
|
||||
|
||||
// Notification
|
||||
case "n":
|
||||
log("Notification: " + message.data.slice(1))
|
||||
addScript(message.data.slice(1), true);
|
||||
break;
|
||||
|
||||
// Binding
|
||||
case "b":
|
||||
var binding = message.data.slice(1)
|
||||
//log("Binding: " + binding)
|
||||
window.wails._.newBinding(binding);
|
||||
break;
|
||||
|
||||
// Call back
|
||||
case "c":
|
||||
var callbackData = message.data.slice(1);
|
||||
log("Callback = " + callbackData);
|
||||
window.wails._.callback(callbackData);
|
||||
break;
|
||||
|
||||
// CSS
|
||||
case "s":
|
||||
addScript(message.data.slice(1), true);
|
||||
break;
|
||||
|
||||
// JS
|
||||
case "j":
|
||||
addScript(message.data.slice(1));
|
||||
break;
|
||||
|
||||
// HTML
|
||||
case "h":
|
||||
addScript(message.data.slice(1), true);
|
||||
break;
|
||||
|
||||
default:
|
||||
log("Ignored message: " + message.data.slice(0, 100))
|
||||
}
|
||||
}
|
||||
|
||||
connect();
|
||||
|
||||
}());
|
||||
|
||||
</script>
|
||||
|
||||
</body>
|
||||
|
||||
</html>
|
||||
@@ -163,8 +163,71 @@ func (b *bindingManager) bind(object interface{}) {
|
||||
b.objectsToBind = append(b.objectsToBind, object)
|
||||
}
|
||||
|
||||
func (b *bindingManager) processFunctionCall(callData *callData) (interface{}, error) {
|
||||
// Return values
|
||||
var result []reflect.Value
|
||||
var err error
|
||||
|
||||
function := b.functions[callData.BindingName]
|
||||
if function == nil {
|
||||
return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName)
|
||||
}
|
||||
result, err = function.call(callData.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do we have an error return type?
|
||||
if function.hasErrorReturnType {
|
||||
// We do - last result is an error type
|
||||
// Check if the last result was nil
|
||||
b.log.Debugf("# of return types: %d", len(function.returnTypes))
|
||||
b.log.Debugf("# of results: %d", len(result))
|
||||
errorResult := result[len(function.returnTypes)-1]
|
||||
if !errorResult.IsNil() {
|
||||
// It wasn't - we have an error
|
||||
return nil, errorResult.Interface().(error)
|
||||
}
|
||||
}
|
||||
return result[0].Interface(), nil
|
||||
}
|
||||
|
||||
func (b *bindingManager) processMethodCall(callData *callData) (interface{}, error) {
|
||||
// Return values
|
||||
var result []reflect.Value
|
||||
var err error
|
||||
|
||||
// do we have this method?
|
||||
method := b.methods[callData.BindingName]
|
||||
if method == nil {
|
||||
return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName)
|
||||
}
|
||||
|
||||
result, err = method.call(callData.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do we have an error return type?
|
||||
if method.hasErrorReturnType {
|
||||
// We do - last result is an error type
|
||||
// Check if the last result was nil
|
||||
b.log.Debugf("# of return types: %d", len(method.returnTypes))
|
||||
b.log.Debugf("# of results: %d", len(result))
|
||||
errorResult := result[len(method.returnTypes)-1]
|
||||
if !errorResult.IsNil() {
|
||||
// It wasn't - we have an error
|
||||
return nil, errorResult.Interface().(error)
|
||||
}
|
||||
}
|
||||
if result != nil {
|
||||
return result[0].Interface(), nil
|
||||
}
|
||||
return nil, nil
|
||||
}
|
||||
|
||||
// process an incoming call request
|
||||
func (b *bindingManager) processCall(callData *callData) (interface{}, error) {
|
||||
func (b *bindingManager) processCall(callData *callData) (result interface{}, err error) {
|
||||
b.log.Debugf("Wanting to call %s", callData.BindingName)
|
||||
|
||||
// Determine if this is function call or method call by the number of
|
||||
@@ -176,13 +239,10 @@ func (b *bindingManager) processCall(callData *callData) (interface{}, error) {
|
||||
}
|
||||
}
|
||||
|
||||
// Return values
|
||||
var result []reflect.Value
|
||||
var err error
|
||||
|
||||
// We need to catch reflect related panics and return
|
||||
// a decent error message
|
||||
// TODO: DEBUG THIS!
|
||||
|
||||
defer func() {
|
||||
if r := recover(); r != nil {
|
||||
err = fmt.Errorf("%s", r.(string))
|
||||
@@ -191,59 +251,14 @@ func (b *bindingManager) processCall(callData *callData) (interface{}, error) {
|
||||
|
||||
switch dotCount {
|
||||
case 1:
|
||||
function := b.functions[callData.BindingName]
|
||||
if function == nil {
|
||||
return nil, fmt.Errorf("Invalid function name '%s'", callData.BindingName)
|
||||
}
|
||||
result, err = function.call(callData.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do we have an error return type?
|
||||
if function.hasErrorReturnType {
|
||||
// We do - last result is an error type
|
||||
// Check if the last result was nil
|
||||
b.log.Debugf("# of return types: %d", len(function.returnTypes))
|
||||
b.log.Debugf("# of results: %d", len(result))
|
||||
errorResult := result[len(function.returnTypes)-1]
|
||||
if !errorResult.IsNil() {
|
||||
// It wasn't - we have an error
|
||||
return nil, errorResult.Interface().(error)
|
||||
}
|
||||
}
|
||||
return result[0].Interface(), nil
|
||||
result, err = b.processFunctionCall(callData)
|
||||
case 2:
|
||||
// do we have this method?
|
||||
method := b.methods[callData.BindingName]
|
||||
if method == nil {
|
||||
return nil, fmt.Errorf("Invalid method name '%s'", callData.BindingName)
|
||||
}
|
||||
result, err = method.call(callData.Data)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Do we have an error return type?
|
||||
if method.hasErrorReturnType {
|
||||
// We do - last result is an error type
|
||||
// Check if the last result was nil
|
||||
b.log.Debugf("# of return types: %d", len(method.returnTypes))
|
||||
b.log.Debugf("# of results: %d", len(result))
|
||||
errorResult := result[len(method.returnTypes)-1]
|
||||
if !errorResult.IsNil() {
|
||||
// It wasn't - we have an error
|
||||
return nil, errorResult.Interface().(error)
|
||||
}
|
||||
}
|
||||
if result != nil {
|
||||
return result[0].Interface(), nil
|
||||
}
|
||||
return nil, nil
|
||||
|
||||
result, err = b.processMethodCall(callData)
|
||||
default:
|
||||
return nil, fmt.Errorf("Invalid binding name '%s'", callData.BindingName)
|
||||
result = nil
|
||||
err = fmt.Errorf("Invalid binding name '%s'", callData.BindingName)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// callWailsInitMethods calls all of the WailsInit methods that were
|
||||
|
||||
@@ -1,69 +0,0 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
"io/ioutil"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
)
|
||||
|
||||
// FrameworkMetadata contains information about a given framework
|
||||
type FrameworkMetadata struct {
|
||||
Name string `json:"name"`
|
||||
BuildTag string `json:"buildtag"`
|
||||
Description string `json:"description"`
|
||||
}
|
||||
|
||||
// Utility function for creating new FrameworkMetadata structs
|
||||
func loadFrameworkMetadata(pathToMetadataJSON string) (*FrameworkMetadata, error) {
|
||||
result := &FrameworkMetadata{}
|
||||
configData, err := ioutil.ReadFile(pathToMetadataJSON)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
// Load and unmarshall!
|
||||
err = json.Unmarshal(configData, result)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
return result, nil
|
||||
}
|
||||
|
||||
// GetFrameworks returns information about all the available frameworks
|
||||
func GetFrameworks() ([]*FrameworkMetadata, error) {
|
||||
|
||||
var err error
|
||||
|
||||
// Calculate framework base dir
|
||||
_, filename, _, _ := runtime.Caller(1)
|
||||
frameworksBaseDir := filepath.Join(path.Dir(filename), "frameworks")
|
||||
|
||||
// Get the subdirectories
|
||||
fs := NewFSHelper()
|
||||
frameworkDirs, err := fs.GetSubdirs(frameworksBaseDir)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
|
||||
// Prepare result
|
||||
result := []*FrameworkMetadata{}
|
||||
|
||||
// Iterate framework directories, looking for metadata.json files
|
||||
for _, frameworkDir := range frameworkDirs {
|
||||
var frameworkMetadata FrameworkMetadata
|
||||
metadataFile := filepath.Join(frameworkDir, "metadata.json")
|
||||
jsonData, err := ioutil.ReadFile(metadataFile)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
err = json.Unmarshal(jsonData, &frameworkMetadata)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
}
|
||||
result = append(result, &frameworkMetadata)
|
||||
}
|
||||
|
||||
// Read in framework metadata
|
||||
return result, nil
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,16 +0,0 @@
|
||||
// +build frameworkbootstrap4
|
||||
|
||||
package frameworks
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr"
|
||||
)
|
||||
|
||||
func init() {
|
||||
assets := packr.NewBox("./bootstrap4default/assets")
|
||||
FrameworkToUse = &Framework{
|
||||
Name: "Bootstrap 4",
|
||||
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
|
||||
CSS: BoxString(&assets, "bootstrap.min.css"),
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2018 Twitter, Inc.
|
||||
Copyright (c) 2011-2018 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,17 +0,0 @@
|
||||
// +build frameworkbootstrap4
|
||||
|
||||
package bootstrap4
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr"
|
||||
"github.com/wailsapp/wails/frameworks"
|
||||
)
|
||||
|
||||
func init() {
|
||||
assets := packr.NewBox("./assets")
|
||||
frameworks.FrameworkToUse = &frameworks.Framework{
|
||||
Name: "Bootstrap 4",
|
||||
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
|
||||
CSS: BoxString(&assets, "bootstrap.min.css"),
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"Name": "Bootstrap 4",
|
||||
"Description": "Standard Bootstrap 4 with default theme",
|
||||
"BuildTag": "frameworkbootstrap4"
|
||||
}
|
||||
@@ -1,16 +0,0 @@
|
||||
// +build frameworkbootstrap4lux
|
||||
|
||||
package frameworks
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr"
|
||||
)
|
||||
|
||||
func init() {
|
||||
assets := packr.NewBox("./bootstrap4lux/assets")
|
||||
FrameworkToUse = &Framework{
|
||||
Name: "Bootstrap 4 (Lux)",
|
||||
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
|
||||
CSS: BoxString(&assets, "bootstrap.min.css"),
|
||||
}
|
||||
}
|
||||
File diff suppressed because one or more lines are too long
@@ -1,22 +0,0 @@
|
||||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2011-2018 Twitter, Inc.
|
||||
Copyright (c) 2011-2018 The Bootstrap Authors
|
||||
|
||||
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||
of this software and associated documentation files (the "Software"), to deal
|
||||
in the Software without restriction, including without limitation the rights
|
||||
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||
copies of the Software, and to permit persons to whom the Software is
|
||||
furnished to do so, subject to the following conditions:
|
||||
|
||||
The above copyright notice and this permission notice shall be included in
|
||||
all copies or substantial portions of the Software.
|
||||
|
||||
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||
THE SOFTWARE.
|
||||
File diff suppressed because one or more lines are too long
File diff suppressed because one or more lines are too long
@@ -1,17 +0,0 @@
|
||||
// +build frameworkbootstrap4lux
|
||||
|
||||
package bootstrap4
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr"
|
||||
"github.com/wailsapp/wails/frameworks"
|
||||
)
|
||||
|
||||
func init() {
|
||||
assets := packr.NewBox("./assets")
|
||||
frameworks.FrameworkToUse = &frameworks.Framework{
|
||||
Name: "Bootstrap 4 (Lux)",
|
||||
JS: BoxString(&assets, "bootstrap.bundle.min.js"),
|
||||
CSS: BoxString(&assets, "bootstrap.min.css"),
|
||||
}
|
||||
}
|
||||
@@ -1,5 +0,0 @@
|
||||
{
|
||||
"Name": "Bootstrap 4 (Lux)",
|
||||
"Description": "Bootstrap with Lux theme",
|
||||
"BuildTag": "frameworkbootstrap4lux"
|
||||
}
|
||||
@@ -1,28 +0,0 @@
|
||||
package frameworks
|
||||
|
||||
import (
|
||||
"log"
|
||||
|
||||
"github.com/gobuffalo/packr"
|
||||
)
|
||||
|
||||
// Framework has details about a specific framework
|
||||
type Framework struct {
|
||||
Name string
|
||||
JS string
|
||||
CSS string
|
||||
Options string
|
||||
}
|
||||
|
||||
// FrameworkToUse is the framework we will use when building
|
||||
// Set by `wails init`, used by `wails build`
|
||||
var FrameworkToUse *Framework
|
||||
|
||||
// BoxString extracts a string from a packr box
|
||||
func BoxString(box *packr.Box, filename string) string {
|
||||
result, err := box.FindString(filename)
|
||||
if err != nil {
|
||||
log.Fatal(err)
|
||||
}
|
||||
return result
|
||||
}
|
||||
232
cmd/helpers.go
Normal file
232
cmd/helpers.go
Normal file
@@ -0,0 +1,232 @@
|
||||
package cmd
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
"os/exec"
|
||||
"path"
|
||||
"path/filepath"
|
||||
"runtime"
|
||||
"time"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/leaanthony/spinner"
|
||||
)
|
||||
|
||||
// ValidateFrontendConfig checks if the frontend config is valid
|
||||
func ValidateFrontendConfig(projectOptions *ProjectOptions) error {
|
||||
if projectOptions.FrontEnd.Dir == "" {
|
||||
return fmt.Errorf("Frontend directory not set in project.json")
|
||||
}
|
||||
if projectOptions.FrontEnd.Build == "" {
|
||||
return fmt.Errorf("Frontend build command not set in project.json")
|
||||
}
|
||||
if projectOptions.FrontEnd.Install == "" {
|
||||
return fmt.Errorf("Frontend install command not set in project.json")
|
||||
}
|
||||
if projectOptions.FrontEnd.Bridge == "" {
|
||||
return fmt.Errorf("Frontend bridge config not set in project.json")
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallGoDependencies will run go get in the current directory
|
||||
func InstallGoDependencies() error {
|
||||
depSpinner := spinner.New("Installing Dependencies...")
|
||||
depSpinner.SetSpinSpeed(50)
|
||||
depSpinner.Start()
|
||||
err := NewProgramHelper().RunCommand("go get")
|
||||
if err != nil {
|
||||
depSpinner.Error()
|
||||
return err
|
||||
}
|
||||
depSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildApplication will attempt to build the project based on the given inputs
|
||||
func BuildApplication(binaryName string, forceRebuild bool, buildMode string) error {
|
||||
compileMessage := "Packing + Compiling project"
|
||||
if buildMode == "debug" {
|
||||
compileMessage += " (Debug Mode)"
|
||||
}
|
||||
|
||||
packSpinner := spinner.New(compileMessage + "...")
|
||||
packSpinner.SetSpinSpeed(50)
|
||||
packSpinner.Start()
|
||||
|
||||
buildCommand := slicer.String()
|
||||
buildCommand.AddSlice([]string{"packr", "build"})
|
||||
|
||||
if binaryName != "" {
|
||||
buildCommand.Add("-o")
|
||||
buildCommand.Add(binaryName)
|
||||
}
|
||||
|
||||
// If we are forcing a rebuild
|
||||
if forceRebuild {
|
||||
buildCommand.Add("-a")
|
||||
}
|
||||
|
||||
// Setup ld flags
|
||||
ldflags := "-w -s "
|
||||
if buildMode == "debug" {
|
||||
ldflags = ""
|
||||
}
|
||||
ldflags += "-X github.com/wailsapp/wails.BuildMode=" + buildMode
|
||||
|
||||
buildCommand.AddSlice([]string{"-ldflags", ldflags})
|
||||
err := NewProgramHelper().RunCommandArray(buildCommand.AsSlice())
|
||||
if err != nil {
|
||||
packSpinner.Error()
|
||||
return err
|
||||
}
|
||||
packSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
// PackageApplication will attempt to package the application in a pltform dependent way
|
||||
func PackageApplication(projectOptions *ProjectOptions) error {
|
||||
// Package app
|
||||
packageSpinner := spinner.New("Packaging Application")
|
||||
packageSpinner.SetSpinSpeed(50)
|
||||
packageSpinner.Start()
|
||||
err := NewPackageHelper().Package(projectOptions)
|
||||
if err != nil {
|
||||
packageSpinner.Error()
|
||||
return err
|
||||
}
|
||||
packageSpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
// BuildFrontend runs the given build command
|
||||
func BuildFrontend(buildCommand string) error {
|
||||
buildFESpinner := spinner.New("Building frontend...")
|
||||
buildFESpinner.SetSpinSpeed(50)
|
||||
buildFESpinner.Start()
|
||||
err := NewProgramHelper().RunCommand(buildCommand)
|
||||
if err != nil {
|
||||
buildFESpinner.Error()
|
||||
return err
|
||||
}
|
||||
buildFESpinner.Success()
|
||||
return nil
|
||||
}
|
||||
|
||||
// CheckPackr checks if packr is installed and if not, attempts to fetch it
|
||||
func CheckPackr() (err error) {
|
||||
programHelper := NewProgramHelper()
|
||||
if !programHelper.IsInstalled("packr") {
|
||||
buildSpinner := spinner.New()
|
||||
buildSpinner.SetSpinSpeed(50)
|
||||
buildSpinner.Start("Installing packr...")
|
||||
err := programHelper.InstallGoPackage("github.com/gobuffalo/packr/...")
|
||||
if err != nil {
|
||||
buildSpinner.Error()
|
||||
return err
|
||||
}
|
||||
buildSpinner.Success()
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// InstallFrontendDeps attempts to install the frontend dependencies based on the given options
|
||||
func InstallFrontendDeps(projectDir string, projectOptions *ProjectOptions, forceRebuild bool) error {
|
||||
|
||||
// Install frontend deps
|
||||
err := os.Chdir(projectOptions.FrontEnd.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if frontend deps have been updated
|
||||
feSpinner := spinner.New("Installing frontend dependencies (This may take a while)...")
|
||||
feSpinner.SetSpinSpeed(50)
|
||||
feSpinner.Start()
|
||||
|
||||
requiresNPMInstall := true
|
||||
|
||||
// Read in package.json MD5
|
||||
fs := NewFSHelper()
|
||||
packageJSONMD5, err := fs.FileMD5("package.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const md5sumFile = "package.json.md5"
|
||||
|
||||
// If we aren't forcing the install and the md5sum file exists
|
||||
if !forceRebuild && fs.FileExists(md5sumFile) {
|
||||
// Yes - read contents
|
||||
savedMD5sum, err := fs.LoadAsString(md5sumFile)
|
||||
// File exists
|
||||
if err == nil {
|
||||
// Compare md5
|
||||
if savedMD5sum == packageJSONMD5 {
|
||||
// Same - no need for reinstall
|
||||
requiresNPMInstall = false
|
||||
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Md5 sum package.json
|
||||
// Different? Build
|
||||
if requiresNPMInstall || forceRebuild {
|
||||
// Install dependencies
|
||||
err = NewProgramHelper().RunCommand(projectOptions.FrontEnd.Install)
|
||||
if err != nil {
|
||||
feSpinner.Error()
|
||||
return err
|
||||
}
|
||||
feSpinner.Success()
|
||||
|
||||
// Update md5sum file
|
||||
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||
}
|
||||
|
||||
bridgeFile := "wailsbridge.prod.js"
|
||||
|
||||
// Copy bridge to project
|
||||
_, filename, _, _ := runtime.Caller(1)
|
||||
bridgeFileSource := filepath.Join(path.Dir(filename), "..", "..", "assets", "default", bridgeFile)
|
||||
bridgeFileTarget := filepath.Join(projectDir, projectOptions.FrontEnd.Dir, projectOptions.FrontEnd.Bridge, "wailsbridge.js")
|
||||
err = fs.CopyFile(bridgeFileSource, bridgeFileTarget)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build frontend
|
||||
err = BuildFrontend(projectOptions.FrontEnd.Build)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ServeProject attempts to serve up the current project so that it may be connected to
|
||||
// via the Wails bridge
|
||||
func ServeProject(projectOptions *ProjectOptions, logger *Logger) error {
|
||||
go func() {
|
||||
time.Sleep(2 * time.Second)
|
||||
logger.Green(">>>>> To connect, you will need to run '" + projectOptions.FrontEnd.Serve + "' in the '" + projectOptions.FrontEnd.Dir + "' directory <<<<<")
|
||||
}()
|
||||
location, err := filepath.Abs(projectOptions.BinaryName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Yellow("Serving Application: " + location)
|
||||
cmd := exec.Command(location)
|
||||
cmd.Stdout = os.Stdout
|
||||
cmd.Stderr = os.Stderr
|
||||
err = cmd.Run()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
@@ -116,6 +116,7 @@ func (p *ProgramHelper) RunCommandArray(args []string) error {
|
||||
return err
|
||||
}
|
||||
args = args[1:]
|
||||
// fmt.Printf("RunCommandArray = %s %+v\n", program, args)
|
||||
_, stderr, err := p.shell.Run(program, args...)
|
||||
if err != nil {
|
||||
fmt.Println(stderr)
|
||||
|
||||
191
cmd/project.go
191
cmd/project.go
@@ -19,6 +19,8 @@ type frontend struct {
|
||||
Dir string `json:"dir"`
|
||||
Install string `json:"install"`
|
||||
Build string `json:"build"`
|
||||
Bridge string `json:"bridge"`
|
||||
Serve string `json:"serve"`
|
||||
}
|
||||
|
||||
type framework struct {
|
||||
@@ -151,17 +153,16 @@ func InputQuestion(name, message string, defaultValue string, required bool) *su
|
||||
|
||||
// ProjectOptions holds all the options available for a project
|
||||
type ProjectOptions struct {
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Author *author `json:"author,omitempty"`
|
||||
Version string `json:"version"`
|
||||
OutputDirectory string `json:"-"`
|
||||
UseDefaults bool `json:"-"`
|
||||
Template string `json:"-"`
|
||||
BinaryName string `json:"binaryname"`
|
||||
FrontEnd *frontend `json:"frontend,omitempty"`
|
||||
NPMProjectName string `json:"-"`
|
||||
Framework *framework `json:"framework,omitempty"`
|
||||
Name string `json:"name"`
|
||||
Description string `json:"description"`
|
||||
Author *author `json:"author,omitempty"`
|
||||
Version string `json:"version"`
|
||||
OutputDirectory string `json:"-"`
|
||||
UseDefaults bool `json:"-"`
|
||||
Template string `json:"-"`
|
||||
BinaryName string `json:"binaryname"`
|
||||
FrontEnd *frontend `json:"frontend,omitempty"`
|
||||
NPMProjectName string `json:"-"`
|
||||
system *SystemHelper
|
||||
log *Logger
|
||||
templates *TemplateHelper
|
||||
@@ -177,40 +178,14 @@ func (po *ProjectOptions) Defaults() {
|
||||
func (po *ProjectOptions) PromptForInputs() error {
|
||||
|
||||
var questions []*survey.Question
|
||||
fs := NewFSHelper()
|
||||
|
||||
if po.Name == "" {
|
||||
questions = append(questions, InputQuestion("Name", "The name of the project", "My Project", true))
|
||||
} else {
|
||||
fmt.Println("Project Name: " + po.Name)
|
||||
}
|
||||
processProjectName(po.Name, &questions)
|
||||
|
||||
if po.BinaryName == "" {
|
||||
var binaryNameComputed string
|
||||
if po.Name != "" {
|
||||
binaryNameComputed = strings.ToLower(po.Name)
|
||||
binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1)
|
||||
binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1)
|
||||
binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1)
|
||||
}
|
||||
questions = append(questions, InputQuestion("BinaryName", "The output binary name", binaryNameComputed, true))
|
||||
} else {
|
||||
fmt.Println("Output binary Name: " + po.BinaryName)
|
||||
}
|
||||
processBinaryName(po.BinaryName, po.Name, &questions)
|
||||
|
||||
if po.OutputDirectory != "" {
|
||||
projectPath, err := filepath.Abs(po.OutputDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if fs.DirExists(projectPath) {
|
||||
return fmt.Errorf("directory '%s' already exists", projectPath)
|
||||
}
|
||||
|
||||
fmt.Println("Project Directory: " + po.OutputDirectory)
|
||||
} else {
|
||||
questions = append(questions, InputQuestion("OutputDirectory", "Project directory name", "", true))
|
||||
err := processOutputDirectory(po.OutputDirectory, &questions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
templateDetails, err := po.templates.GetTemplateDetails()
|
||||
@@ -251,38 +226,6 @@ func (po *ProjectOptions) PromptForInputs() error {
|
||||
// Setup NPM Project name
|
||||
po.NPMProjectName = strings.ToLower(strings.Replace(po.Name, " ", "_", -1))
|
||||
|
||||
// If we selected custom, prompt for framework
|
||||
if po.Template == "custom - Choose your own CSS Framework" {
|
||||
// Ask for the framework
|
||||
var frameworkName string
|
||||
frameworks, err := GetFrameworks()
|
||||
frameworkNames := []string{}
|
||||
metadataMap := make(map[string]*FrameworkMetadata)
|
||||
for _, frameworkMetadata := range frameworks {
|
||||
frameworkDetails := fmt.Sprintf("%s - %s", frameworkMetadata.Name, frameworkMetadata.Description)
|
||||
metadataMap[frameworkDetails] = frameworkMetadata
|
||||
frameworkNames = append(frameworkNames, frameworkDetails)
|
||||
}
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
var frameworkQuestion []*survey.Question
|
||||
frameworkQuestion = append(frameworkQuestion, SelectQuestion("Framework", "Select framework", frameworkNames, frameworkNames[0], true))
|
||||
err = survey.Ask(frameworkQuestion, &frameworkName)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
// Get metadata
|
||||
metadata := metadataMap[frameworkName]
|
||||
|
||||
// Add to project config
|
||||
po.Framework = &framework{
|
||||
Name: metadata.Name,
|
||||
BuildTag: metadata.BuildTag,
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// Fix template name
|
||||
if po.templateNameMap[po.Template] != "" {
|
||||
po.Template = po.templateNameMap[po.Template]
|
||||
@@ -290,21 +233,10 @@ func (po *ProjectOptions) PromptForInputs() error {
|
||||
|
||||
// Populate template details
|
||||
templateMetadata := templateDetails[po.Template].Metadata
|
||||
if templateMetadata["frontenddir"] != nil {
|
||||
po.FrontEnd = &frontend{}
|
||||
po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
|
||||
}
|
||||
if templateMetadata["install"] != nil {
|
||||
if po.FrontEnd == nil {
|
||||
return fmt.Errorf("install set in template metadata but not frontenddir")
|
||||
}
|
||||
po.FrontEnd.Install = templateMetadata["install"].(string)
|
||||
}
|
||||
if templateMetadata["build"] != nil {
|
||||
if po.FrontEnd == nil {
|
||||
return fmt.Errorf("build set in template metadata but not frontenddir")
|
||||
}
|
||||
po.FrontEnd.Build = templateMetadata["build"].(string)
|
||||
|
||||
err = processTemplateMetadata(templateMetadata, po)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return nil
|
||||
@@ -337,3 +269,84 @@ func (po *ProjectOptions) LoadConfig(projectDir string) error {
|
||||
}
|
||||
return json.Unmarshal(rawBytes, po)
|
||||
}
|
||||
|
||||
func computeBinaryName(projectName string) string {
|
||||
if projectName == "" {
|
||||
return ""
|
||||
}
|
||||
var binaryNameComputed = strings.ToLower(projectName)
|
||||
binaryNameComputed = strings.Replace(binaryNameComputed, " ", "-", -1)
|
||||
binaryNameComputed = strings.Replace(binaryNameComputed, string(filepath.Separator), "-", -1)
|
||||
binaryNameComputed = strings.Replace(binaryNameComputed, ":", "-", -1)
|
||||
return binaryNameComputed
|
||||
}
|
||||
|
||||
func processOutputDirectory(outputDirectory string, questions *[]*survey.Question) error {
|
||||
|
||||
if outputDirectory != "" {
|
||||
projectPath, err := filepath.Abs(outputDirectory)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
if NewFSHelper().DirExists(projectPath) {
|
||||
return fmt.Errorf("directory '%s' already exists", projectPath)
|
||||
}
|
||||
|
||||
fmt.Println("Project Directory: " + outputDirectory)
|
||||
} else {
|
||||
*questions = append(*questions, InputQuestion("OutputDirectory", "Project directory name", "", true))
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func processProjectName(name string, questions *[]*survey.Question) {
|
||||
if name == "" {
|
||||
*questions = append(*questions, InputQuestion("Name", "The name of the project", "My Project", true))
|
||||
} else {
|
||||
fmt.Println("Project Name: " + name)
|
||||
}
|
||||
}
|
||||
|
||||
func processBinaryName(binaryName string, name string, questions *[]*survey.Question) {
|
||||
if binaryName == "" {
|
||||
var binaryNameComputed = computeBinaryName(name)
|
||||
*questions = append(*questions, InputQuestion("BinaryName", "The output binary name", binaryNameComputed, true))
|
||||
} else {
|
||||
fmt.Println("Output binary Name: " + binaryName)
|
||||
}
|
||||
}
|
||||
|
||||
func processTemplateMetadata(templateMetadata map[string]interface{}, po *ProjectOptions) error {
|
||||
if templateMetadata["frontenddir"] != nil {
|
||||
po.FrontEnd = &frontend{}
|
||||
po.FrontEnd.Dir = templateMetadata["frontenddir"].(string)
|
||||
}
|
||||
if templateMetadata["install"] != nil {
|
||||
if po.FrontEnd == nil {
|
||||
return fmt.Errorf("install set in template metadata but not frontenddir")
|
||||
}
|
||||
po.FrontEnd.Install = templateMetadata["install"].(string)
|
||||
}
|
||||
if templateMetadata["build"] != nil {
|
||||
if po.FrontEnd == nil {
|
||||
return fmt.Errorf("build set in template metadata but not frontenddir")
|
||||
}
|
||||
po.FrontEnd.Build = templateMetadata["build"].(string)
|
||||
}
|
||||
|
||||
if templateMetadata["bridge"] != nil {
|
||||
if po.FrontEnd == nil {
|
||||
return fmt.Errorf("bridge set in template metadata but not frontenddir")
|
||||
}
|
||||
po.FrontEnd.Bridge = templateMetadata["bridge"].(string)
|
||||
}
|
||||
|
||||
if templateMetadata["serve"] != nil {
|
||||
if po.FrontEnd == nil {
|
||||
return fmt.Errorf("serve set in template metadata but not frontenddir")
|
||||
}
|
||||
po.FrontEnd.Serve = templateMetadata["serve"].(string)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
@@ -1,8 +0,0 @@
|
||||
<div style="text-align:center">
|
||||
<div
|
||||
class="wails-logo"
|
||||
style="width: 25rem;margin: auto;height: 25rem;"
|
||||
></div>
|
||||
<h1>Basic Template</h1>
|
||||
Welcome to your basic Wails app!
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
module {{.BinaryName}}
|
||||
@@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr"
|
||||
wails "github.com/wailsapp/wails"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Assets
|
||||
assets := packr.NewBox("./frontend")
|
||||
|
||||
// Initialise the app
|
||||
app := wails.CreateApp(&wails.AppConfig{
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
Title: "{{.Name}}",
|
||||
HTML: wails.BoxString(&assets, "main.html"),
|
||||
})
|
||||
app.Run()
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "Basic",
|
||||
"shortdescription": "A basic template",
|
||||
"description": "A basic template using vanilla JS",
|
||||
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
||||
"created": "2018-10-18"
|
||||
}
|
||||
@@ -1,8 +0,0 @@
|
||||
<div style="text-align:center">
|
||||
<div
|
||||
class="wails-logo"
|
||||
style="width: 25rem;margin: auto;height: 25rem;"
|
||||
></div>
|
||||
<h1>Custom CSS Template</h1>
|
||||
Welcome to your basic Wails app with custom CSS!
|
||||
</div>
|
||||
@@ -1 +0,0 @@
|
||||
module {{.BinaryName}}
|
||||
@@ -1,21 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"github.com/gobuffalo/packr"
|
||||
wails "github.com/wailsapp/wails"
|
||||
)
|
||||
|
||||
func main() {
|
||||
|
||||
// Assets
|
||||
assets := packr.NewBox("./frontend")
|
||||
|
||||
// Initialise the app
|
||||
app := wails.CreateApp(&wails.AppConfig{
|
||||
Width: 1024,
|
||||
Height: 768,
|
||||
Title: "{{.Name}}",
|
||||
HTML: wails.BoxString(&assets, "main.html"),
|
||||
})
|
||||
app.Run()
|
||||
}
|
||||
@@ -1,7 +0,0 @@
|
||||
{
|
||||
"name": "Custom",
|
||||
"shortdescription": "Choose your own CSS Framework",
|
||||
"description": "A basic template allowing use of CSS Frameworks",
|
||||
"author": "Lea Anthony<lea.anthony@gmail.com>",
|
||||
"created": "2018-10-22"
|
||||
}
|
||||
@@ -12,8 +12,8 @@ html {
|
||||
overflow: hidden;
|
||||
/* https://leaverou.github.io/css3patterns/#carbon */
|
||||
background: linear-gradient(27deg, #151515 5px, transparent 5px) 0 5px,
|
||||
linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0px,
|
||||
linear-gradient(27deg, #222 5px, transparent 5px) 0px 10px,
|
||||
linear-gradient(207deg, #151515 5px, transparent 5px) 10px 0,
|
||||
linear-gradient(27deg, #222 5px, transparent 5px) 0 10px,
|
||||
linear-gradient(207deg, #222 5px, transparent 5px) 10px 5px,
|
||||
linear-gradient(90deg, #1b1b1b 10px, transparent 10px),
|
||||
linear-gradient(
|
||||
@@ -46,10 +46,8 @@ html {
|
||||
format("woff2"),
|
||||
/* Super Modern Browsers */
|
||||
url("../fonts/roboto/roboto-v18-latin-regular.woff") format("woff"),
|
||||
/* Modern Browsers */
|
||||
url("../fonts/roboto/roboto-v18-latin-regular.ttf")
|
||||
/* Modern Browsers */ url("../fonts/roboto/roboto-v18-latin-regular.ttf")
|
||||
format("truetype"),
|
||||
/* Safari, Android, iOS */
|
||||
url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto")
|
||||
format("svg"); /* Legacy iOS */
|
||||
}
|
||||
url("../fonts/roboto/roboto-v18-latin-regular.svg#Roboto") format("svg"); /* Legacy iOS */
|
||||
}
|
||||
|
||||
@@ -18,8 +18,12 @@ body {
|
||||
border-color: #117;
|
||||
}
|
||||
|
||||
p { margin-bottom: 1.5em; }
|
||||
p:last-child { margin-bottom: 0; }
|
||||
p {
|
||||
margin-bottom: 1.5em;
|
||||
}
|
||||
p:last-child {
|
||||
margin-bottom: 0;
|
||||
}
|
||||
|
||||
blockquote {
|
||||
display: block;
|
||||
@@ -32,9 +36,9 @@ blockquote {
|
||||
color: #117;
|
||||
}
|
||||
blockquote:before {
|
||||
content: '\201C';
|
||||
content: "\201C";
|
||||
position: absolute;
|
||||
top: 0em;
|
||||
top: 0;
|
||||
left: 50%;
|
||||
transform: translate(-50%, -50%);
|
||||
background: #fff;
|
||||
@@ -54,22 +58,22 @@ blockquote:after {
|
||||
|
||||
/* https://fdossena.com/?p=html5cool/buttons/i.frag */
|
||||
button {
|
||||
display:inline-block;
|
||||
padding:0.35em 1.2em;
|
||||
border:0.1em solid #000;
|
||||
margin:0 0.3em 0.3em 0;
|
||||
border-radius:0.12em;
|
||||
display: inline-block;
|
||||
padding: 0.35em 1.2em;
|
||||
border: 0.1em solid #000;
|
||||
margin: 0 0.3em 0.3em 0;
|
||||
border-radius: 0.12em;
|
||||
box-sizing: border-box;
|
||||
text-decoration:none;
|
||||
font-family:'Roboto',sans-serif;
|
||||
font-weight:300;
|
||||
text-decoration: none;
|
||||
font-family: "Roboto", sans-serif;
|
||||
font-weight: 300;
|
||||
font-size: 1em;
|
||||
color:#000;
|
||||
text-align:center;
|
||||
color: #000;
|
||||
text-align: center;
|
||||
transition: all 0.2s;
|
||||
}
|
||||
button:hover{
|
||||
color:#FFF;
|
||||
background-color:#000;
|
||||
button:hover {
|
||||
color: #fff;
|
||||
background-color: #000;
|
||||
cursor: pointer;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -25,7 +25,11 @@ export default {
|
||||
}
|
||||
},
|
||||
created() {
|
||||
if( !backend ) {
|
||||
eventBus.$on("ready", this.getNewQuote);
|
||||
} else {
|
||||
this.getNewQuote();
|
||||
}
|
||||
}
|
||||
};
|
||||
</script>
|
||||
|
||||
@@ -7,8 +7,7 @@ new Vue({
|
||||
}).$mount("#app");
|
||||
|
||||
import Bridge from "./wailsbridge";
|
||||
Bridge.Start(startApp);
|
||||
|
||||
function startApp() {
|
||||
Bridge.OnReady(() => {
|
||||
eventBus.$emit("ready");
|
||||
}
|
||||
});
|
||||
Bridge.Start();
|
||||
|
||||
@@ -6,5 +6,7 @@
|
||||
"created": "2018-12-01",
|
||||
"frontenddir": "frontend",
|
||||
"install": "npm install",
|
||||
"build": "npm run build"
|
||||
}
|
||||
"build": "npm run build",
|
||||
"serve": "npm run serve",
|
||||
"bridge": "src"
|
||||
}
|
||||
|
||||
@@ -2,4 +2,4 @@ package cmd
|
||||
|
||||
// Version - Wails version
|
||||
// ...oO(There must be a better way)
|
||||
const Version = "v0.5.0"
|
||||
const Version = "v0.8.0"
|
||||
|
||||
@@ -5,7 +5,6 @@ import (
|
||||
"runtime"
|
||||
|
||||
"github.com/leaanthony/spinner"
|
||||
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
@@ -31,64 +30,29 @@ Create your first project by running 'wails init'.`
|
||||
if runtime.GOOS != "windows" {
|
||||
successMessage = "🚀 " + successMessage
|
||||
}
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
logger.Yellow("Detected Platform: OSX")
|
||||
case "windows":
|
||||
logger.Yellow("Detected Platform: Windows")
|
||||
case "linux":
|
||||
logger.Yellow("Detected Platform: Linux")
|
||||
default:
|
||||
return fmt.Errorf("Platform %s is currently not supported", runtime.GOOS)
|
||||
}
|
||||
|
||||
logger.Yellow("Checking for prerequisites...")
|
||||
// Check we have a cgo capable environment
|
||||
|
||||
requiredPrograms, err := cmd.GetRequiredPrograms()
|
||||
// Platform check
|
||||
err = platformCheck()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
errors := false
|
||||
programHelper := cmd.NewProgramHelper()
|
||||
for _, program := range *requiredPrograms {
|
||||
bin := programHelper.FindProgram(program.Name)
|
||||
if bin == nil {
|
||||
errors = true
|
||||
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
|
||||
} else {
|
||||
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
|
||||
}
|
||||
|
||||
// Check we have a cgo capable environment
|
||||
logger.Yellow("Checking for prerequisites...")
|
||||
errors, err := checkRequiredPrograms()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Linux has library deps
|
||||
if runtime.GOOS == "linux" {
|
||||
// Check library prerequisites
|
||||
requiredLibraries, err := cmd.GetRequiredLibraries()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
distroInfo := cmd.GetLinuxDistroInfo()
|
||||
for _, library := range *requiredLibraries {
|
||||
switch distroInfo.Distribution {
|
||||
case cmd.Ubuntu:
|
||||
installed, err := cmd.DpkgInstalled(library.Name)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
default:
|
||||
return fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
|
||||
}
|
||||
}
|
||||
errors, err = checkLibraries()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// packr
|
||||
err = cmd.CheckPackr()
|
||||
|
||||
programHelper := cmd.NewProgramHelper()
|
||||
if !programHelper.IsInstalled("packr") {
|
||||
buildSpinner := spinner.New()
|
||||
buildSpinner.SetSpinSpeed(50)
|
||||
@@ -110,3 +74,65 @@ Create your first project by running 'wails init'.`
|
||||
return err
|
||||
})
|
||||
}
|
||||
|
||||
func platformCheck() error {
|
||||
switch runtime.GOOS {
|
||||
case "darwin":
|
||||
logger.Yellow("Detected Platform: OSX")
|
||||
case "windows":
|
||||
logger.Yellow("Detected Platform: Windows")
|
||||
case "linux":
|
||||
logger.Yellow("Detected Platform: Linux")
|
||||
default:
|
||||
return fmt.Errorf("Platform %s is currently not supported", runtime.GOOS)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func checkLibraries() (errors bool, err error) {
|
||||
if runtime.GOOS == "linux" {
|
||||
// Check library prerequisites
|
||||
requiredLibraries, err := cmd.GetRequiredLibraries()
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
distroInfo := cmd.GetLinuxDistroInfo()
|
||||
for _, library := range *requiredLibraries {
|
||||
switch distroInfo.Distribution {
|
||||
case cmd.Ubuntu:
|
||||
installed, err := cmd.DpkgInstalled(library.Name)
|
||||
if err != nil {
|
||||
return false, err
|
||||
}
|
||||
if !installed {
|
||||
errors = true
|
||||
logger.Red("Library '%s' not found. %s", library.Name, library.Help)
|
||||
} else {
|
||||
logger.Green("Library '%s' installed.", library.Name)
|
||||
}
|
||||
default:
|
||||
return false, fmt.Errorf("unable to check libraries on distribution '%s'. Please ensure that the '%s' equivalent is installed", distroInfo.DistributorID, library.Name)
|
||||
}
|
||||
}
|
||||
}
|
||||
return false, nil
|
||||
}
|
||||
|
||||
func checkRequiredPrograms() (errors bool, err error) {
|
||||
requiredPrograms, err := cmd.GetRequiredPrograms()
|
||||
if err != nil {
|
||||
return true, err
|
||||
}
|
||||
errors = false
|
||||
programHelper := cmd.NewProgramHelper()
|
||||
for _, program := range *requiredPrograms {
|
||||
bin := programHelper.FindProgram(program.Name)
|
||||
if bin == nil {
|
||||
errors = true
|
||||
logger.Red("Program '%s' not found. %s", program.Name, program.Help)
|
||||
} else {
|
||||
logger.Green("Program '%s' found: %s", program.Name, bin.Path)
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
@@ -1,251 +0,0 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"io/ioutil"
|
||||
"os"
|
||||
|
||||
"github.com/leaanthony/slicer"
|
||||
"github.com/leaanthony/spinner"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
var packageApp = false
|
||||
var forceRebuild = false
|
||||
var releaseMode = false
|
||||
buildSpinner := spinner.NewSpinner()
|
||||
buildSpinner.SetSpinSpeed(50)
|
||||
|
||||
commandDescription := `This command will check to ensure all pre-requistes are installed prior to building. If not, it will attempt to install them. Building comprises of a number of steps: install frontend dependencies, build frontend, pack frontend, compile main application.`
|
||||
initCmd := app.Command("build", "Builds your Wails project").
|
||||
LongDescription(commandDescription).
|
||||
BoolFlag("p", "Package application on successful build (Implies -r)", &packageApp).
|
||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||
BoolFlag("r", "Build in Release mode", &releaseMode)
|
||||
|
||||
initCmd.Action(func() error {
|
||||
log := cmd.NewLogger()
|
||||
message := "Building Application"
|
||||
if forceRebuild {
|
||||
message += " (force rebuild)"
|
||||
}
|
||||
log.WhiteUnderline(message)
|
||||
|
||||
// Project options
|
||||
projectOptions := &cmd.ProjectOptions{}
|
||||
|
||||
// Check we are in project directory
|
||||
// Check project.json loads correctly
|
||||
fs := cmd.NewFSHelper()
|
||||
err := projectOptions.LoadConfig(fs.Cwd())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate config
|
||||
// Check if we have a frontend
|
||||
if projectOptions.FrontEnd != nil {
|
||||
if projectOptions.FrontEnd.Dir == "" {
|
||||
return fmt.Errorf("Frontend directory not set in project.json")
|
||||
}
|
||||
if projectOptions.FrontEnd.Build == "" {
|
||||
return fmt.Errorf("Frontend build command not set in project.json")
|
||||
}
|
||||
if projectOptions.FrontEnd.Install == "" {
|
||||
return fmt.Errorf("Frontend install command not set in project.json")
|
||||
}
|
||||
}
|
||||
|
||||
// Check pre-requisites are installed
|
||||
|
||||
// Program checker
|
||||
program := cmd.NewProgramHelper()
|
||||
|
||||
if projectOptions.FrontEnd != nil {
|
||||
// npm
|
||||
if !program.IsInstalled("npm") {
|
||||
return fmt.Errorf("it appears npm is not installed. Please install and run again")
|
||||
}
|
||||
}
|
||||
|
||||
// packr
|
||||
if !program.IsInstalled("packr") {
|
||||
buildSpinner.Start("Installing packr...")
|
||||
err := program.InstallGoPackage("github.com/gobuffalo/packr/...")
|
||||
if err != nil {
|
||||
buildSpinner.Error()
|
||||
return err
|
||||
}
|
||||
buildSpinner.Success()
|
||||
}
|
||||
|
||||
// Save project directory
|
||||
projectDir := fs.Cwd()
|
||||
|
||||
// Install backend deps - needed?
|
||||
if projectOptions.FrontEnd != nil {
|
||||
// Install frontend deps
|
||||
err = os.Chdir(projectOptions.FrontEnd.Dir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Check if frontend deps have been updated
|
||||
feSpinner := spinner.New("Installing frontend dependencies (This may take a while)...")
|
||||
feSpinner.SetSpinSpeed(50)
|
||||
feSpinner.Start()
|
||||
|
||||
requiresNPMInstall := true
|
||||
|
||||
// Read in package.json MD5
|
||||
packageJSONMD5, err := fs.FileMD5("package.json")
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
const md5sumFile = "package.json.md5"
|
||||
|
||||
// If we aren't forcing the install and the md5sum file exists
|
||||
if !forceRebuild && fs.FileExists(md5sumFile) {
|
||||
// Yes - read contents
|
||||
savedMD5sum, err := fs.LoadAsString(md5sumFile)
|
||||
// File exists
|
||||
if err == nil {
|
||||
// Compare md5
|
||||
if savedMD5sum == packageJSONMD5 {
|
||||
// Same - no need for reinstall
|
||||
requiresNPMInstall = false
|
||||
feSpinner.Success("Skipped frontend dependencies (-f to force rebuild)")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Md5 sum package.json
|
||||
// Different? Build
|
||||
if requiresNPMInstall || forceRebuild {
|
||||
// Install dependencies
|
||||
err = program.RunCommand(projectOptions.FrontEnd.Install)
|
||||
if err != nil {
|
||||
feSpinner.Error()
|
||||
return err
|
||||
}
|
||||
feSpinner.Success()
|
||||
|
||||
// Update md5sum file
|
||||
ioutil.WriteFile(md5sumFile, []byte(packageJSONMD5), 0644)
|
||||
}
|
||||
|
||||
// Build frontend
|
||||
buildFESpinner := spinner.New("Building frontend...")
|
||||
buildFESpinner.SetSpinSpeed(50)
|
||||
buildFESpinner.Start()
|
||||
err = program.RunCommand(projectOptions.FrontEnd.Build)
|
||||
if err != nil {
|
||||
buildFESpinner.Error()
|
||||
return err
|
||||
}
|
||||
buildFESpinner.Success()
|
||||
}
|
||||
|
||||
// Run packr in project directory
|
||||
err = os.Chdir(projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Support build tags
|
||||
buildTags := []string{}
|
||||
|
||||
// Do we have any frameworks specified?
|
||||
frameworkSpinner := spinner.New()
|
||||
frameworkSpinner.SetSpinSpeed(50)
|
||||
if projectOptions.Framework != nil {
|
||||
frameworkSpinner.Start()
|
||||
frameworkSpinner.Success("Compiling support for " + projectOptions.Framework.Name)
|
||||
buildTags = append(buildTags, projectOptions.Framework.BuildTag)
|
||||
}
|
||||
|
||||
// // Initialise Go Module - if go.mod doesn't exist
|
||||
// if !fs.FileExists("go.mod") {
|
||||
// buildSpinner.Start("Initialising Go module...")
|
||||
// err = program.RunCommand("go mod init " + projectOptions.BinaryName)
|
||||
// if err != nil {
|
||||
// buildSpinner.Error()
|
||||
// return err
|
||||
// }
|
||||
// buildSpinner.Success()
|
||||
// }
|
||||
|
||||
depSpinner := spinner.New("Installing Dependencies...")
|
||||
depSpinner.SetSpinSpeed(50)
|
||||
depSpinner.Start()
|
||||
installCommand := "go get"
|
||||
err = program.RunCommand(installCommand)
|
||||
if err != nil {
|
||||
depSpinner.Error()
|
||||
return err
|
||||
}
|
||||
depSpinner.Success()
|
||||
|
||||
compileMessage := "Packing + Compiling project"
|
||||
if releaseMode || packageApp {
|
||||
compileMessage += " (Release Mode)"
|
||||
}
|
||||
|
||||
packSpinner := spinner.New(compileMessage + "...")
|
||||
packSpinner.SetSpinSpeed(50)
|
||||
packSpinner.Start()
|
||||
|
||||
buildCommand := slicer.String()
|
||||
buildCommand.AddSlice([]string{"packr", "build"})
|
||||
|
||||
// Add build tags
|
||||
if len(buildTags) > 0 {
|
||||
buildCommand.Add("--tags")
|
||||
buildCommand.AddSlice(buildTags)
|
||||
|
||||
}
|
||||
|
||||
if projectOptions.BinaryName != "" {
|
||||
buildCommand.Add("-o")
|
||||
buildCommand.Add(projectOptions.BinaryName)
|
||||
}
|
||||
|
||||
// If we are forcing a rebuild
|
||||
if forceRebuild {
|
||||
buildCommand.Add("-a")
|
||||
}
|
||||
|
||||
// Release mode
|
||||
if releaseMode || packageApp {
|
||||
buildCommand.AddSlice([]string{"-ldflags", "-X github.com/wailsapp/wails.DebugMode=false"})
|
||||
}
|
||||
err = program.RunCommandArray(buildCommand.AsSlice())
|
||||
if err != nil {
|
||||
packSpinner.Error()
|
||||
return err
|
||||
}
|
||||
packSpinner.Success()
|
||||
|
||||
if packageApp == false {
|
||||
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||
return nil
|
||||
}
|
||||
|
||||
// Package app
|
||||
packageSpinner := spinner.New("Packaging Application")
|
||||
packageSpinner.SetSpinSpeed(50)
|
||||
packageSpinner.Start()
|
||||
packager := cmd.NewPackageHelper()
|
||||
err = packager.Package(projectOptions)
|
||||
if err != nil {
|
||||
packageSpinner.Error()
|
||||
return err
|
||||
}
|
||||
packageSpinner.Success()
|
||||
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||
return nil
|
||||
})
|
||||
}
|
||||
114
cmd/wails/4_build.go
Normal file
114
cmd/wails/4_build.go
Normal file
@@ -0,0 +1,114 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/leaanthony/spinner"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
var packageApp = false
|
||||
var forceRebuild = false
|
||||
var debugMode = false
|
||||
buildSpinner := spinner.NewSpinner()
|
||||
buildSpinner.SetSpinSpeed(50)
|
||||
|
||||
commandDescription := `This command will check to ensure all pre-requistes are installed prior to building. If not, it will attempt to install them. Building comprises of a number of steps: install frontend dependencies, build frontend, pack frontend, compile main application.`
|
||||
initCmd := app.Command("build", "Builds your Wails project").
|
||||
LongDescription(commandDescription).
|
||||
BoolFlag("p", "Package application on successful build", &packageApp).
|
||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild).
|
||||
BoolFlag("d", "Build in Debug mode", &debugMode)
|
||||
|
||||
initCmd.Action(func() error {
|
||||
log := cmd.NewLogger()
|
||||
message := "Building Application"
|
||||
if forceRebuild {
|
||||
message += " (force rebuild)"
|
||||
}
|
||||
log.WhiteUnderline(message)
|
||||
|
||||
// Project options
|
||||
projectOptions := &cmd.ProjectOptions{}
|
||||
|
||||
// Check we are in project directory
|
||||
// Check project.json loads correctly
|
||||
fs := cmd.NewFSHelper()
|
||||
err := projectOptions.LoadConfig(fs.Cwd())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate config
|
||||
// Check if we have a frontend
|
||||
err = cmd.ValidateFrontendConfig(projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Program checker
|
||||
program := cmd.NewProgramHelper()
|
||||
|
||||
if projectOptions.FrontEnd != nil {
|
||||
// npm
|
||||
if !program.IsInstalled("npm") {
|
||||
return fmt.Errorf("it appears npm is not installed. Please install and run again")
|
||||
}
|
||||
}
|
||||
|
||||
// Check Packr is installed
|
||||
err = cmd.CheckPackr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save project directory
|
||||
projectDir := fs.Cwd()
|
||||
|
||||
// Install deps
|
||||
if projectOptions.FrontEnd != nil {
|
||||
err = cmd.InstallFrontendDeps(projectDir, projectOptions, forceRebuild)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Move to project directory
|
||||
err = os.Chdir(projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Install dependencies
|
||||
err = cmd.InstallGoDependencies()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Build application
|
||||
buildMode := "prod"
|
||||
if debugMode {
|
||||
buildMode = "debug"
|
||||
}
|
||||
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Package application
|
||||
if packageApp {
|
||||
err = cmd.PackageApplication(projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||
|
||||
return nil
|
||||
|
||||
})
|
||||
}
|
||||
96
cmd/wails/6_serve.go
Normal file
96
cmd/wails/6_serve.go
Normal file
@@ -0,0 +1,96 @@
|
||||
package main
|
||||
|
||||
import (
|
||||
"fmt"
|
||||
"os"
|
||||
|
||||
"github.com/leaanthony/spinner"
|
||||
"github.com/wailsapp/wails/cmd"
|
||||
)
|
||||
|
||||
func init() {
|
||||
|
||||
var forceRebuild = false
|
||||
buildSpinner := spinner.NewSpinner()
|
||||
buildSpinner.SetSpinSpeed(50)
|
||||
|
||||
commandDescription := `This command builds then serves your application in bridge mode. Useful for developing your app in a browser.`
|
||||
initCmd := app.Command("serve", "Run your Wails project in bridge mode.").
|
||||
LongDescription(commandDescription).
|
||||
BoolFlag("f", "Force rebuild of application components", &forceRebuild)
|
||||
|
||||
initCmd.Action(func() error {
|
||||
log := cmd.NewLogger()
|
||||
message := "Building Application"
|
||||
if forceRebuild {
|
||||
message += " (force rebuild)"
|
||||
}
|
||||
log.WhiteUnderline(message)
|
||||
|
||||
// Project options
|
||||
projectOptions := &cmd.ProjectOptions{}
|
||||
|
||||
// Check we are in project directory
|
||||
// Check project.json loads correctly
|
||||
fs := cmd.NewFSHelper()
|
||||
err := projectOptions.LoadConfig(fs.Cwd())
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Validate config
|
||||
// Check if we have a frontend
|
||||
err = cmd.ValidateFrontendConfig(projectOptions)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Program checker
|
||||
program := cmd.NewProgramHelper()
|
||||
|
||||
if projectOptions.FrontEnd != nil {
|
||||
// npm
|
||||
if !program.IsInstalled("npm") {
|
||||
return fmt.Errorf("it appears npm is not installed. Please install and run again")
|
||||
}
|
||||
}
|
||||
|
||||
// Check Packr is installed
|
||||
err = cmd.CheckPackr()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Save project directory
|
||||
projectDir := fs.Cwd()
|
||||
|
||||
// Install deps
|
||||
if projectOptions.FrontEnd != nil {
|
||||
err = cmd.InstallFrontendDeps(projectDir, projectOptions, forceRebuild)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
// Run packr in project directory
|
||||
err = os.Chdir(projectDir)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
// Install dependencies
|
||||
err = cmd.InstallGoDependencies()
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
buildMode := "bridge"
|
||||
err = cmd.BuildApplication(projectOptions.BinaryName, forceRebuild, buildMode)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
logger.Yellow("Awesome! Project '%s' built!", projectOptions.Name)
|
||||
return cmd.ServeProject(projectOptions, logger)
|
||||
})
|
||||
}
|
||||
7
go.mod
7
go.mod
@@ -13,15 +13,12 @@ require (
|
||||
github.com/jackmordaunt/icns v1.0.0
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 // indirect
|
||||
github.com/leaanthony/slicer v0.0.0-20190110113548-aa9ea12f976a
|
||||
github.com/leaanthony/spinner v0.4.0
|
||||
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 // indirect
|
||||
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15 // indirect
|
||||
github.com/mattn/go-colorable v0.0.9 // indirect
|
||||
github.com/mattn/go-isatty v0.0.4 // indirect
|
||||
github.com/leaanthony/spinner v0.5.0
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b // indirect
|
||||
github.com/mitchellh/go-homedir v1.0.0
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 // indirect
|
||||
github.com/sirupsen/logrus v1.2.0
|
||||
github.com/wailsapp/webview v0.2.0
|
||||
golang.org/x/net v0.0.0-20190107155100-1a61f4433d85 // indirect
|
||||
gopkg.in/AlecAivazis/survey.v1 v1.7.1 // indirect
|
||||
)
|
||||
|
||||
32
go.sum
32
go.sum
@@ -3,7 +3,6 @@ github.com/AlecAivazis/survey v1.7.1/go.mod h1:MVECab6WqEH1aXhj8nKIwF7HEAJAj2bhh
|
||||
github.com/BurntSushi/toml v0.3.1/go.mod h1:xHWCNGjB5oqiDr8zfno3MHue2Ht5sIBksp03qcyfWMU=
|
||||
github.com/Masterminds/semver v1.4.2/go.mod h1:MB6lktGJrhw8PrUyiEoblNEGEQ+RzHPF078ddwwvV3Y=
|
||||
github.com/ajg/form v0.0.0-20160822230020-523a5da1a92f/go.mod h1:uL1WgH+h2mgNtvBq0339dVnzXdBETtL2LeUXaIv25UY=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc h1:cAKDfWh5VpdgMhJosfJnn5/FoN2SRZ4p7fJNX58YPaU=
|
||||
github.com/alecthomas/template v0.0.0-20160405071501-a0175ee3bccc/go.mod h1:LOuyumcjzFXgccqObfd/Ljyb9UuFJ6TxHnclSeseNhc=
|
||||
github.com/armon/consul-api v0.0.0-20180202201655-eb2c6b5be1b6/go.mod h1:grANhF5doyWs3UAsr3K4I6qtAmlQcZDesFNEHPZAzj8=
|
||||
github.com/cockroachdb/apd v1.1.0/go.mod h1:8Sl8LxpKi29FqWXR16WEFZRNSz3SoPzUzeMeY4+DwBQ=
|
||||
@@ -187,6 +186,8 @@ github.com/gobuffalo/x v0.0.0-20181007152206-913e47c59ca7/go.mod h1:9rDPXaB3kXdK
|
||||
github.com/gofrs/uuid v3.1.0+incompatible/go.mod h1:b2aQJv3Z4Fp6yNu3cdSllBxTCLRxnplIgP/c0N/04lM=
|
||||
github.com/golang/protobuf v1.1.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
|
||||
github.com/google/go-github v17.0.0+incompatible/go.mod h1:zLgOLi98H3fifZn+44m+umXrS52loVEgC2AApnigrVQ=
|
||||
github.com/google/go-querystring v1.0.0/go.mod h1:odCYkC5MyYFN7vkCjXpyrEuKhc/BUO6wN/zVPAxq5ck=
|
||||
github.com/gorilla/context v1.1.1/go.mod h1:kBGZzfjB9CEq2AlWe17Uuf7NDRt0dE0s8S51q0aT7Yg=
|
||||
github.com/gorilla/mux v1.6.2/go.mod h1:1lud6UwP+6orDFRuTfBEV8e9/aOM/c4fVVCaMa2zaAs=
|
||||
github.com/gorilla/pat v0.0.0-20180118222023-199c85a7f6d1/go.mod h1:YeAe0gNeiNT5hoiZRI4yiOky6jVdNvfO2N6Kav/HmxY=
|
||||
@@ -211,7 +212,6 @@ github.com/karrick/godirwalk v1.7.7/go.mod h1:2c9FRhkDxdIbgkOnCEvnSWs71Bhugbl46s
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51 h1:Z9n2FFNUXsshfwJMBgNA0RU6/i7WVaAegv3PtuIHPMs=
|
||||
github.com/kballard/go-shellquote v0.0.0-20180428030007-95032a82bc51/go.mod h1:CzGEWj7cYgsdH8dAjBGEr58BoE7ScuLd+fwFZ44+/x8=
|
||||
github.com/konsorten/go-windows-terminal-sequences v0.0.0-20180402223658-b729f2633dfe/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1 h1:mweAR1A6xJ3oS2pRaGiHgQ4OO8tzTaLawm8vnODuwDk=
|
||||
github.com/konsorten/go-windows-terminal-sequences v1.0.1/go.mod h1:T0+1ngSBFLxvqU3pZ+m/2kptfBszLMUkC4ZK/EgS/cQ=
|
||||
github.com/kr/pretty v0.1.0/go.mod h1:dAy3ld7l9f0ibDNOQOHHMYYIIbhfbHSm3C4ZsoJORNo=
|
||||
github.com/kr/pty v1.1.1/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
@@ -219,14 +219,11 @@ github.com/kr/pty v1.1.3/go.mod h1:pFQYn66WHrOpPYNljwOMqo10TkYh1fy3cYio2l3bCsQ=
|
||||
github.com/kr/text v0.1.0/go.mod h1:4Jbv+DJW3UT/LiOwJeYQe1efqtUx/iVham/4vfdArNI=
|
||||
github.com/leaanthony/slicer v0.0.0-20190110113548-aa9ea12f976a h1:+nH6CKt4ZdMj+AabQrU0SLtZWYyQ1ovzLCA21se+raw=
|
||||
github.com/leaanthony/slicer v0.0.0-20190110113548-aa9ea12f976a/go.mod h1:VMB/HGvr3uR3MRpFWHWAm0w+DHQLzPHYe2pKfpFlQIQ=
|
||||
github.com/leaanthony/spinner v0.4.0 h1:y/7FqQqqObRKYI+33bg9DGhHIY7cQHicm+Vz0Uda0Ik=
|
||||
github.com/leaanthony/spinner v0.4.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
|
||||
github.com/leaanthony/spinner v0.5.0 h1:OJKn+0KP6ilHxwCEOv5Lo0wPM4PgWZWLJTeUprGJK0g=
|
||||
github.com/leaanthony/spinner v0.5.0/go.mod h1:2Mmv+8Brcw3NwPT1DdOLmW6+zWpSamDDFFsUvVHo2cc=
|
||||
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0 h1:1bGojw4YacLY5bqQalojiQ7mSfQbe4WIWCEgPZagowU=
|
||||
github.com/leaanthony/synx v0.0.0-20180923230033-60efbd9984b0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15 h1:166LIty6ldcyOc7tbgfu5smsGATvEo0JZV6bnbzyEc4=
|
||||
github.com/leaanthony/wincursor v0.0.0-20180705115120-056510f32d15/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||
github.com/leaanthony/spinner v0.5.0 h1:HQykt/iTy7fmINEREtRbWrt+8j4MxC8dtvWBxEWM9oA=
|
||||
github.com/leaanthony/spinner v0.5.0/go.mod h1:8TSFz9SL1AUC4XSbEFYE6SfN5Mlus51qYluVGrie9ww=
|
||||
github.com/leaanthony/synx v0.1.0 h1:R0lmg2w6VMb8XcotOwAe5DLyzwjLrskNkwU7LLWsyL8=
|
||||
github.com/leaanthony/synx v0.1.0/go.mod h1:Iz7eybeeG8bdq640iR+CwYb8p+9EOsgMWghkSRyZcqs=
|
||||
github.com/leaanthony/wincursor v0.1.0/go.mod h1:7TVwwrzSH/2Y9gLOGH+VhA+bZhoWXBRgbGNTMk+yimE=
|
||||
github.com/lib/pq v1.0.0/go.mod h1:5WUZQaWbwv1U+lTReE5YruASi9Al49XbQIvNi/34Woo=
|
||||
github.com/magiconair/properties v1.8.0/go.mod h1:PppfXfuXeibc/6YijjN8zIbojt8czPbwD3XqdrwzmxQ=
|
||||
github.com/markbates/deplist v1.0.4/go.mod h1:gRRbPbbuA8TmMiRvaOzUlRfzfjeCCBqX2A6arxN01MM=
|
||||
@@ -252,6 +249,7 @@ github.com/mattn/go-colorable v0.0.9 h1:UVL0vNpWh04HeJXV0KLcaT7r06gOH2l4OW6ddYRU
|
||||
github.com/mattn/go-colorable v0.0.9/go.mod h1:9vuHe8Xs5qXnSaW/c/ABM9alt+Vo+STaOChaDxuIBZU=
|
||||
github.com/mattn/go-isatty v0.0.4 h1:bnP0vzxcAdeI1zdubAl5PjU6zsERjGZb7raWodagDYs=
|
||||
github.com/mattn/go-isatty v0.0.4/go.mod h1:M+lRXTBqGeGNdLjl/ufCoiOlB5xdOkqRJdNxMWT7Zi4=
|
||||
github.com/mattn/go-runewidth v0.0.4/go.mod h1:LwmH8dsx7+W8Uxz3IHJYH5QSwggIsqBzpuz5H//U1FU=
|
||||
github.com/mattn/go-sqlite3 v1.9.0/go.mod h1:FPy6KqzDD04eiIsT53CuJW3U88zkxoIYsOqkbpncsNc=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b h1:j7+1HpAFS1zy5+Q4qx1fWh90gTKwiN4QCGoY9TWyyO4=
|
||||
github.com/mgutz/ansi v0.0.0-20170206155736-9520e82c474b/go.mod h1:01TrycV0kFyexm33Z7vhZRXopbI8J3TDReVlkTgMUxE=
|
||||
@@ -264,6 +262,7 @@ github.com/monoculum/formam v0.0.0-20180901015400-4e68be1d79ba/go.mod h1:RKgILGE
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646 h1:zYyBkD/k9seD2A7fsi6Oo2LfFZAehjjQMERAvZLEDnQ=
|
||||
github.com/nfnt/resize v0.0.0-20180221191011-83c6a9932646/go.mod h1:jpp1/29i3P1S/RLdc7JQKbRpFeM1dOBd8T9ki5s+AY8=
|
||||
github.com/nicksnyder/go-i18n v1.10.0/go.mod h1:HrK7VCrbOvQoUAQ7Vpy7i87N7JZZZ7R2xBGjv0j365Q=
|
||||
github.com/olekukonko/tablewriter v0.0.1/go.mod h1:vsDQFd/mU46D+Z4whnwzcISnGGzXWMclvtLoiIKAKIo=
|
||||
github.com/onsi/ginkgo v1.6.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/ginkgo v1.7.0/go.mod h1:lLunBs/Ym6LB5Z9jYTR76FiuTmxDTDusOGeTQH+WWjE=
|
||||
github.com/onsi/gomega v1.4.1/go.mod h1:C1qb7wdrVGGVU+Z6iS04AVkA3Q65CEZX59MT0QO5uiA=
|
||||
@@ -273,6 +272,7 @@ github.com/pelletier/go-toml v1.2.0/go.mod h1:5z9KED0ma1S8pY6P1sdut58dfprrGBbd/9
|
||||
github.com/pkg/errors v0.8.0 h1:WdK/asTD0HN+q6hsWO3/vpuAkAr+tw6aNJNDFFf0+qw=
|
||||
github.com/pkg/errors v0.8.0/go.mod h1:bwawxfHBFNV+L2hUp1rHADufV3IMtnDRdf1r5NINEl0=
|
||||
github.com/pmezard/go-difflib v1.0.0/go.mod h1:iKH77koFhYxTK1pcRnkKkqfTogsbg7gZNVY4sRDYZ/4=
|
||||
github.com/ribice/glice v0.0.0-20181011133736-685f13fa9b12/go.mod h1:A+ednilkKNW0CJGLsrLkq0D49M4EhlCi8gvnkwoZFn0=
|
||||
github.com/rogpeppe/go-internal v1.0.0 h1:o4VLZ5jqHE+HahLT6drNtSGTrrUA3wPBmtpgqtdbClo=
|
||||
github.com/rogpeppe/go-internal v1.0.0/go.mod h1:M8bDsm7K2OlrFYOpmOWEs/qY81heoFRclV5y23lUDJ4=
|
||||
github.com/satori/go.uuid v1.2.0/go.mod h1:dA0hQrYB0VpLJoorglMZABFdXlWrHn1NEOzdhQKdks0=
|
||||
@@ -306,8 +306,12 @@ github.com/stretchr/testify v1.2.2/go.mod h1:a8OnRcib4nhh0OaRAV+Yts87kKdq0PP7pXf
|
||||
github.com/ugorji/go/codec v0.0.0-20181204163529-d75b2dcb6bc8/go.mod h1:VFNgLljTbGfSG7qAOspJ7OScBnGdDN/yBr0sguwnwf0=
|
||||
github.com/unrolled/secure v0.0.0-20180918153822-f340ee86eb8b/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
||||
github.com/unrolled/secure v0.0.0-20181005190816-ff9db2ff917f/go.mod h1:mnPT77IAdsi/kV7+Es7y+pXALeV3h7G6dQF6mNYjcLA=
|
||||
github.com/wailsapp/wails v0.0.0-20181215232634-5de8efff325d h1:lk91T4sKD98eGcaz/xC6ER+3o9Kaun7Mk8e/cNZOPMc=
|
||||
github.com/wailsapp/webview v0.0.0-20190206214557-b5fea5042a9e h1:ZT5ZZWHIKrzXWAPME5rcbt1G4sgFyPF9FucugY60jV0=
|
||||
github.com/wailsapp/webview v0.0.0-20190206214557-b5fea5042a9e/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
|
||||
github.com/wailsapp/webview v0.2.0 h1:V3j112ECWIo6LSspWKyiBlEbQAhEPu+bnT1AK8eFNr4=
|
||||
github.com/wailsapp/webview v0.2.0/go.mod h1:XO9HJbKWokDxUYTWQEBCYg95n/To1v7PxvanDNVf8hY=
|
||||
github.com/xordataexchange/crypt v0.0.3-0.20170626215501-b2862e3d0a77/go.mod h1:aYKd//L2LvnjZzWKhF00oedf4jCCReLcmhLdhm1A27Q=
|
||||
github.com/zserge/webview v0.0.0-20190123072648-16c93bcaeaeb/go.mod h1:a1CV8KR4Dd1eP2g+mEijGOp+HKczwdKHWyx0aPHKvo4=
|
||||
golang.org/x/crypto v0.0.0-20180904163835-0709b304e793/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20180910181607-0e37d006457b/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
golang.org/x/crypto v0.0.0-20181001203147-e3636079e1a4/go.mod h1:6SG95UA2DQfeDnfUPMdvaQW0Q7yPrPDi9nlGo2tz2b4=
|
||||
@@ -333,10 +337,11 @@ golang.org/x/net v0.0.0-20181023162649-9b4f9f5ad519/go.mod h1:mL1N/T3taQHkDXs73r
|
||||
golang.org/x/net v0.0.0-20181102091132-c10e9556a7bc/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181106065722-10aee1819953/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181114220301-adae6a3d119a/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380 h1:zPQexyRtNYBc7bcHmehl1dH6TB3qn8zytv8cBGLDNY0=
|
||||
golang.org/x/net v0.0.0-20181207154023-610586996380/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20181220203305-927f97764cc3/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/net v0.0.0-20190107155100-1a61f4433d85 h1:3DfFuyqY+mca6oIDfim5rft3+Kl/CHLe7RdPrUMzwv0=
|
||||
golang.org/x/net v0.0.0-20190107155100-1a61f4433d85/go.mod h1:mL1N/T3taQHkDXs73rZJwtUhF3w3ftmwwsq0BUmARs4=
|
||||
golang.org/x/oauth2 v0.0.0-20181203162652-d668ce993890/go.mod h1:N/0e6XlmueqKjAGxoOufVs8QHGRruUQn6yWY3a++T0U=
|
||||
golang.org/x/sync v0.0.0-20180314180146-1d60e4601c6f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sync v0.0.0-20181108010431-42b317875d0f/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM=
|
||||
golang.org/x/sys v0.0.0-20180816055513-1c9583448a9c/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
@@ -355,8 +360,9 @@ golang.org/x/sys v0.0.0-20181026203630-95b1ffbd15a5/go.mod h1:STP8DvDyc/dI5b8T5h
|
||||
golang.org/x/sys v0.0.0-20181106135930-3a76605856fd/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181107165924-66b7b1311ac8/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181205085412-a5c9d58dba9a/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e h1:njOxP/wVblhCLIUhjHXf6X+dzTt5OQ3vMQo9mkOIKIo=
|
||||
golang.org/x/sys v0.0.0-20181206074257-70b957f3b65e/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb h1:pf3XwC90UUdNPYWZdFjhGBE7DUFuK3Ct1zWmZ65QN30=
|
||||
golang.org/x/sys v0.0.0-20181228144115-9a3f9b0469bb/go.mod h1:STP8DvDyc/dI5b8T5hshtkjS+E42TnysNCUPdjciGhY=
|
||||
golang.org/x/text v0.3.0/go.mod h1:NqM8EUOU14njkJ3fqMW+pc6Ldnwhi/IjpwHt7yyuwOQ=
|
||||
golang.org/x/tools v0.0.0-20180917221912-90fa682c2a6e/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
golang.org/x/tools v0.0.0-20181003024731-2f84ea8ef872/go.mod h1:n7NCudcB/nEzxVGmLbDWY5pfWTLqBcC2KZ6jyYvM4mQ=
|
||||
|
||||
@@ -13,7 +13,6 @@ type Renderer interface {
|
||||
NotifyEvent(eventData *eventData) error
|
||||
|
||||
// Injection
|
||||
InjectFramework(js string, css string)
|
||||
AddJSList(js []string)
|
||||
AddCSSList(css []string)
|
||||
|
||||
|
||||
@@ -11,7 +11,6 @@ import (
|
||||
"github.com/gorilla/websocket"
|
||||
)
|
||||
|
||||
var headlessAssets = packr.NewBox("./assets/headless")
|
||||
var defaultAssets = packr.NewBox("./assets/default")
|
||||
|
||||
type messageType int
|
||||
@@ -48,8 +47,6 @@ type Headless struct {
|
||||
initialisationJS []string
|
||||
server *http.Server
|
||||
theConnection *websocket.Conn
|
||||
bridgeMode bool
|
||||
connectionType string
|
||||
}
|
||||
|
||||
// Initialise the Headless Renderer
|
||||
@@ -57,9 +54,6 @@ func (h *Headless) Initialise(appConfig *AppConfig, ipcManager *ipcManager, even
|
||||
h.ipcManager = ipcManager
|
||||
h.appConfig = appConfig
|
||||
h.eventManager = eventManager
|
||||
h.bridgeMode = false
|
||||
h.connectionType = "Websocket"
|
||||
|
||||
ipcManager.bindRenderer(h)
|
||||
h.log = newCustomLogger("Headless")
|
||||
return nil
|
||||
@@ -95,26 +89,15 @@ func (h *Headless) injectCSS(css string) {
|
||||
h.evalJS(inject, cssMessage)
|
||||
}
|
||||
|
||||
func (h *Headless) rootHandler(w http.ResponseWriter, r *http.Request) {
|
||||
indexHTML := BoxString(&headlessAssets, "index.html")
|
||||
fmt.Fprintf(w, "%s", indexHTML)
|
||||
}
|
||||
|
||||
func (h *Headless) wsBridgeHandler(w http.ResponseWriter, r *http.Request) {
|
||||
h.bridgeMode = true
|
||||
h.connectionType = "Bridge"
|
||||
h.wsHandler(w, r)
|
||||
}
|
||||
|
||||
func (h *Headless) wsHandler(w http.ResponseWriter, r *http.Request) {
|
||||
conn, err := websocket.Upgrade(w, r, w.Header(), 1024, 1024)
|
||||
if err != nil {
|
||||
http.Error(w, "Could not open websocket connection", http.StatusBadRequest)
|
||||
}
|
||||
h.theConnection = conn
|
||||
h.log.Infof("%s connection accepted [%p].", h.connectionType, h.theConnection)
|
||||
h.log.Infof("Connection from frontend accepted.", h.theConnection)
|
||||
conn.SetCloseHandler(func(int, string) error {
|
||||
h.log.Infof("%s connection dropped [%p].", h.connectionType, h.theConnection)
|
||||
h.log.Infof("Connection dropped [%p].", h.theConnection)
|
||||
h.theConnection = nil
|
||||
return nil
|
||||
})
|
||||
@@ -131,17 +114,10 @@ func (h *Headless) start(conn *websocket.Conn) {
|
||||
|
||||
// set external.invoke
|
||||
h.log.Infof("Connected to frontend.")
|
||||
h.log.Infof("Mode = %s", h.connectionType)
|
||||
|
||||
wailsRuntime := BoxString(&defaultAssets, "wails.js")
|
||||
h.evalJS(wailsRuntime, wailsRuntimeMessage)
|
||||
|
||||
if !h.bridgeMode {
|
||||
// Inject jquery
|
||||
jquery := BoxString(&defaultAssets, "jquery.3.3.1.min.js")
|
||||
h.evalJS(jquery, jsMessage)
|
||||
}
|
||||
|
||||
// Inject the initial JS
|
||||
for _, js := range h.initialisationJS {
|
||||
h.sendMessage(h.theConnection, js)
|
||||
@@ -152,60 +128,6 @@ func (h *Headless) start(conn *websocket.Conn) {
|
||||
h.evalJS(binding, bindingMessage)
|
||||
}
|
||||
|
||||
// In Bridge mode, we only send the wails runtime and bindings
|
||||
// so ignore this whole section
|
||||
if !h.bridgeMode {
|
||||
// Inject Framework
|
||||
if h.frameworkJS != "" {
|
||||
h.evalJS(h.frameworkJS, jsMessage)
|
||||
}
|
||||
if h.frameworkCSS != "" {
|
||||
h.injectCSS(h.frameworkCSS)
|
||||
}
|
||||
|
||||
// Inject user CSS
|
||||
if h.appConfig.CSS != "" {
|
||||
outputCSS := fmt.Sprintf("%.45s", h.appConfig.CSS)
|
||||
if len(outputCSS) > 45 {
|
||||
outputCSS += "..."
|
||||
}
|
||||
h.log.DebugFields("Inject User CSS", Fields{"css": outputCSS})
|
||||
h.injectCSS(h.appConfig.CSS)
|
||||
} else {
|
||||
// Use default wails css
|
||||
h.log.Debug("Injecting Default Wails CSS")
|
||||
defaultCSS := BoxString(&defaultAssets, "wails.css")
|
||||
|
||||
h.injectCSS(defaultCSS)
|
||||
}
|
||||
|
||||
// Inject all the CSS files that have been added
|
||||
for _, css := range h.cssCache {
|
||||
h.injectCSS(css)
|
||||
}
|
||||
|
||||
// Inject all the JS files that have been added
|
||||
for _, js := range h.jsCache {
|
||||
h.evalJS(js, jsMessage)
|
||||
}
|
||||
|
||||
// Inject user JS
|
||||
if h.appConfig.JS != "" {
|
||||
outputJS := fmt.Sprintf("%.45s", h.appConfig.JS)
|
||||
if len(outputJS) > 45 {
|
||||
outputJS += "..."
|
||||
}
|
||||
h.log.DebugFields("Inject User JS", Fields{"js": outputJS})
|
||||
h.evalJS(h.appConfig.JS, jsMessage)
|
||||
}
|
||||
|
||||
var injectHTML string
|
||||
if h.appConfig.isHTMLFragment {
|
||||
injectHTML = fmt.Sprintf("$('#app').html('%s')", h.appConfig.HTML)
|
||||
h.evalJS(injectHTML, htmlMessage)
|
||||
}
|
||||
}
|
||||
|
||||
// Emit that everything is loaded and ready
|
||||
h.eventManager.Emit("wails:ready")
|
||||
|
||||
@@ -228,13 +150,10 @@ func (h *Headless) start(conn *websocket.Conn) {
|
||||
// Run the app in headless mode!
|
||||
func (h *Headless) Run() error {
|
||||
h.server = &http.Server{Addr: ":34115"}
|
||||
http.HandleFunc("/ws", h.wsHandler)
|
||||
http.HandleFunc("/bridge", h.wsBridgeHandler)
|
||||
http.HandleFunc("/", h.rootHandler)
|
||||
|
||||
h.log.Info("Headless mode started.")
|
||||
h.log.Info("If using the Wails bridge, it will connect automatically.")
|
||||
h.log.Info("You may also connect manually by browsing to http://localhost:34115")
|
||||
h.log.Info("The Wails bridge will connect automatically.")
|
||||
|
||||
err := h.server.ListenAndServe()
|
||||
if err != nil {
|
||||
@@ -249,13 +168,6 @@ func (h *Headless) NewBinding(methodName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
// InjectFramework sets up what JS/CSS should be injected
|
||||
// at startup
|
||||
func (h *Headless) InjectFramework(js, css string) {
|
||||
h.frameworkJS = js
|
||||
h.frameworkCSS = css
|
||||
}
|
||||
|
||||
// SelectFile is unsupported for Headless but required
|
||||
// for the Renderer interface
|
||||
func (h *Headless) SelectFile() string {
|
||||
|
||||
@@ -9,7 +9,7 @@ import (
|
||||
|
||||
"github.com/go-playground/colors"
|
||||
"github.com/gobuffalo/packr"
|
||||
"github.com/wailsapp/wails/webview"
|
||||
"github.com/wailsapp/webview"
|
||||
)
|
||||
|
||||
// Window defines the main application window
|
||||
@@ -171,10 +171,6 @@ func (w *webViewRenderer) Run() error {
|
||||
|
||||
// Run this in a different go routine to free up the main process
|
||||
go func() {
|
||||
// Will we mount a custom component
|
||||
// Inject jquery
|
||||
jquery := BoxString(&assets, "jquery.3.3.1.min.js")
|
||||
w.evalJSSync(jquery)
|
||||
|
||||
// Inject Bindings
|
||||
for _, binding := range w.bindingCache {
|
||||
@@ -189,17 +185,6 @@ func (w *webViewRenderer) Run() error {
|
||||
w.injectCSS(w.frameworkCSS)
|
||||
}
|
||||
|
||||
// Do we have custom html?
|
||||
// If given an HMTL fragment, mount it on #app
|
||||
// Otherwise, replace the html tag
|
||||
var injectHTML string
|
||||
if w.config.isHTMLFragment {
|
||||
injectHTML = fmt.Sprintf("$('#app').html('%s')", w.config.HTML)
|
||||
} else {
|
||||
injectHTML = fmt.Sprintf("$('html').html('%s')", w.config.HTML)
|
||||
}
|
||||
w.evalJSSync(injectHTML)
|
||||
|
||||
// Inject user CSS
|
||||
if w.config.CSS != "" {
|
||||
outputCSS := fmt.Sprintf("%.45s", w.config.CSS)
|
||||
@@ -254,11 +239,6 @@ func (w *webViewRenderer) NewBinding(methodName string) error {
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *webViewRenderer) InjectFramework(js, css string) {
|
||||
w.frameworkJS = js
|
||||
w.frameworkCSS = css
|
||||
}
|
||||
|
||||
func (w *webViewRenderer) SelectFile() string {
|
||||
var result string
|
||||
|
||||
|
||||
@@ -1,372 +0,0 @@
|
||||
// Package wails implements Go bindings to https://github.com/zserge/webview C library.
|
||||
// It is a modified version of webview.go from that repository
|
||||
|
||||
// Bindings closely repeat the C APIs and include both, a simplified
|
||||
// single-function API to just open a full-screen webview window, and a more
|
||||
// advanced and featureful set of APIs, including Go-to-JavaScript bindings.
|
||||
//
|
||||
// The library uses gtk-webkit, Cocoa/Webkit and MSHTML (IE8..11) as a browser
|
||||
// engine and supports Linux, MacOS and Windows 7..10 respectively.
|
||||
//
|
||||
package webview
|
||||
|
||||
/*
|
||||
#cgo linux openbsd freebsd CFLAGS: -DWEBVIEW_GTK=1
|
||||
#cgo linux openbsd freebsd pkg-config: gtk+-3.0 webkit2gtk-4.0
|
||||
|
||||
#cgo windows CFLAGS: -DWEBVIEW_WINAPI=1
|
||||
#cgo windows LDFLAGS: -lole32 -lcomctl32 -loleaut32 -luuid -lgdi32
|
||||
|
||||
#cgo darwin CFLAGS: -DWEBVIEW_COCOA=1 -x objective-c
|
||||
#cgo darwin LDFLAGS: -framework Cocoa -framework WebKit
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <stdint.h>
|
||||
#define WEBVIEW_STATIC
|
||||
#define WEBVIEW_IMPLEMENTATION
|
||||
#include "webview.h"
|
||||
|
||||
extern void _webviewExternalInvokeCallback(void *, void *);
|
||||
|
||||
static inline void CgoWebViewFree(void *w) {
|
||||
free((void *)((struct webview *)w)->title);
|
||||
free((void *)((struct webview *)w)->url);
|
||||
free(w);
|
||||
}
|
||||
|
||||
static inline void *CgoWebViewCreate(int width, int height, char *title, char *url, int resizable, int debug) {
|
||||
struct webview *w = (struct webview *) calloc(1, sizeof(*w));
|
||||
w->width = width;
|
||||
w->height = height;
|
||||
w->title = title;
|
||||
w->url = url;
|
||||
w->resizable = resizable;
|
||||
w->debug = debug;
|
||||
w->external_invoke_cb = (webview_external_invoke_cb_t) _webviewExternalInvokeCallback;
|
||||
if (webview_init(w) != 0) {
|
||||
CgoWebViewFree(w);
|
||||
return NULL;
|
||||
}
|
||||
return (void *)w;
|
||||
}
|
||||
|
||||
static inline int CgoWebViewLoop(void *w, int blocking) {
|
||||
return webview_loop((struct webview *)w, blocking);
|
||||
}
|
||||
|
||||
static inline void CgoWebViewTerminate(void *w) {
|
||||
webview_terminate((struct webview *)w);
|
||||
}
|
||||
|
||||
static inline void CgoWebViewExit(void *w) {
|
||||
webview_exit((struct webview *)w);
|
||||
}
|
||||
|
||||
static inline void CgoWebViewSetTitle(void *w, char *title) {
|
||||
webview_set_title((struct webview *)w, title);
|
||||
}
|
||||
|
||||
static inline void CgoWebViewSetFullscreen(void *w, int fullscreen) {
|
||||
webview_set_fullscreen((struct webview *)w, fullscreen);
|
||||
}
|
||||
|
||||
static inline void CgoWebViewSetColor(void *w, uint8_t r, uint8_t g, uint8_t b, uint8_t a) {
|
||||
webview_set_color((struct webview *)w, r, g, b, a);
|
||||
}
|
||||
|
||||
static inline void CgoDialog(void *w, int dlgtype, int flags,
|
||||
char *title, char *arg, char *res, size_t ressz) {
|
||||
webview_dialog(w, dlgtype, flags,
|
||||
(const char*)title, (const char*) arg, res, ressz);
|
||||
}
|
||||
|
||||
static inline int CgoWebViewEval(void *w, char *js) {
|
||||
return webview_eval((struct webview *)w, js);
|
||||
}
|
||||
|
||||
static inline void CgoWebViewInjectCSS(void *w, char *css) {
|
||||
webview_inject_css((struct webview *)w, css);
|
||||
}
|
||||
|
||||
extern void _webviewDispatchGoCallback(void *);
|
||||
static inline void _webview_dispatch_cb(struct webview *w, void *arg) {
|
||||
_webviewDispatchGoCallback(arg);
|
||||
}
|
||||
static inline void CgoWebViewDispatch(void *w, uintptr_t arg) {
|
||||
webview_dispatch((struct webview *)w, _webview_dispatch_cb, (void *)arg);
|
||||
}
|
||||
*/
|
||||
import "C"
|
||||
import (
|
||||
"errors"
|
||||
"runtime"
|
||||
"sync"
|
||||
"unsafe"
|
||||
)
|
||||
|
||||
func init() {
|
||||
// Ensure that main.main is called from the main thread
|
||||
runtime.LockOSThread()
|
||||
}
|
||||
|
||||
// Open is a simplified API to open a single native window with a full-size webview in
|
||||
// it. It can be helpful if you want to communicate with the core app using XHR
|
||||
// or WebSockets (as opposed to using JavaScript bindings).
|
||||
//
|
||||
// Window appearance can be customized using title, width, height and resizable parameters.
|
||||
// URL must be provided and can user either a http or https protocol, or be a
|
||||
// local file:// URL. On some platforms "data:" URLs are also supported
|
||||
// (Linux/MacOS).
|
||||
func Open(title, url string, w, h int, resizable bool) error {
|
||||
titleStr := C.CString(title)
|
||||
defer C.free(unsafe.Pointer(titleStr))
|
||||
urlStr := C.CString(url)
|
||||
defer C.free(unsafe.Pointer(urlStr))
|
||||
resize := C.int(0)
|
||||
if resizable {
|
||||
resize = C.int(1)
|
||||
}
|
||||
|
||||
r := C.webview(titleStr, urlStr, C.int(w), C.int(h), resize)
|
||||
if r != 0 {
|
||||
return errors.New("failed to create webview")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ExternalInvokeCallbackFunc is a function type that is called every time
|
||||
// "window.external.invoke()" is called from JavaScript. Data is the only
|
||||
// obligatory string parameter passed into the "invoke(data)" function from
|
||||
// JavaScript. To pass more complex data serialized JSON or base64 encoded
|
||||
// string can be used.
|
||||
type ExternalInvokeCallbackFunc func(w WebView, data string)
|
||||
|
||||
// Settings is a set of parameters to customize the initial WebView appearance
|
||||
// and behavior. It is passed into the webview.New() constructor.
|
||||
type Settings struct {
|
||||
// WebView main window title
|
||||
Title string
|
||||
// URL to open in a webview
|
||||
URL string
|
||||
// Window width in pixels
|
||||
Width int
|
||||
// Window height in pixels
|
||||
Height int
|
||||
// Allows/disallows window resizing
|
||||
Resizable bool
|
||||
// Enable debugging tools (Linux/BSD/MacOS, on Windows use Firebug)
|
||||
Debug bool
|
||||
// A callback that is executed when JavaScript calls "window.external.invoke()"
|
||||
ExternalInvokeCallback ExternalInvokeCallbackFunc
|
||||
}
|
||||
|
||||
// WebView is an interface that wraps the basic methods for controlling the UI
|
||||
// loop, handling multithreading and providing JavaScript bindings.
|
||||
type WebView interface {
|
||||
// Run() starts the main UI loop until the user closes the webview window or
|
||||
// Terminate() is called.
|
||||
Run()
|
||||
// Loop() runs a single iteration of the main UI.
|
||||
Loop(blocking bool) bool
|
||||
// SetTitle() changes window title. This method must be called from the main
|
||||
// thread only. See Dispatch() for more details.
|
||||
SetTitle(title string)
|
||||
// SetFullscreen() controls window full-screen mode. This method must be
|
||||
// called from the main thread only. See Dispatch() for more details.
|
||||
SetFullscreen(fullscreen bool)
|
||||
// SetColor() changes window background color. This method must be called from
|
||||
// the main thread only. See Dispatch() for more details.
|
||||
SetColor(r, g, b, a uint8)
|
||||
// Eval() evaluates an arbitrary JS code inside the webview. This method must
|
||||
// be called from the main thread only. See Dispatch() for more details.
|
||||
Eval(js string) error
|
||||
// InjectJS() injects an arbitrary block of CSS code using the JS API. This
|
||||
// method must be called from the main thread only. See Dispatch() for more
|
||||
// details.
|
||||
InjectCSS(css string)
|
||||
// Dialog() opens a system dialog of the given type and title. String
|
||||
// argument can be provided for certain dialogs, such as alert boxes. For
|
||||
// alert boxes argument is a message inside the dialog box.
|
||||
Dialog(dlgType DialogType, flags int, title string, arg string) string
|
||||
// Terminate() breaks the main UI loop. This method must be called from the main thread
|
||||
// only. See Dispatch() for more details.
|
||||
Terminate()
|
||||
// Dispatch() schedules some arbitrary function to be executed on the main UI
|
||||
// thread. This may be helpful if you want to run some JavaScript from
|
||||
// background threads/goroutines, or to terminate the app.
|
||||
Dispatch(func())
|
||||
// Exit() closes the window and cleans up the resources. Use Terminate() to
|
||||
// forcefully break out of the main UI loop.
|
||||
Exit()
|
||||
}
|
||||
|
||||
// DialogType is an enumeration of all supported system dialog types
|
||||
type DialogType int
|
||||
|
||||
const (
|
||||
// DialogTypeOpen is a system file open dialog
|
||||
DialogTypeOpen DialogType = iota
|
||||
// DialogTypeSave is a system file save dialog
|
||||
DialogTypeSave
|
||||
// DialogTypeAlert is a system alert dialog (message box)
|
||||
DialogTypeAlert
|
||||
)
|
||||
|
||||
const (
|
||||
// DialogFlagFile is a normal file picker dialog
|
||||
DialogFlagFile = C.WEBVIEW_DIALOG_FLAG_FILE
|
||||
// DialogFlagDirectory is an open directory dialog
|
||||
DialogFlagDirectory = C.WEBVIEW_DIALOG_FLAG_DIRECTORY
|
||||
// DialogFlagInfo is an info alert dialog
|
||||
DialogFlagInfo = C.WEBVIEW_DIALOG_FLAG_INFO
|
||||
// DialogFlagWarning is a warning alert dialog
|
||||
DialogFlagWarning = C.WEBVIEW_DIALOG_FLAG_WARNING
|
||||
// DialogFlagError is an error dialog
|
||||
DialogFlagError = C.WEBVIEW_DIALOG_FLAG_ERROR
|
||||
)
|
||||
|
||||
var (
|
||||
m sync.Mutex
|
||||
index uintptr
|
||||
fns = map[uintptr]func(){}
|
||||
cbs = map[WebView]ExternalInvokeCallbackFunc{}
|
||||
)
|
||||
|
||||
type webview struct {
|
||||
w unsafe.Pointer
|
||||
}
|
||||
|
||||
var _ WebView = &webview{}
|
||||
|
||||
func boolToInt(b bool) int {
|
||||
if b {
|
||||
return 1
|
||||
}
|
||||
return 0
|
||||
}
|
||||
|
||||
// NewWebview creates and opens a new webview window using the given settings. The
|
||||
// returned object implements the WebView interface. This function returns nil
|
||||
// if a window can not be created.
|
||||
func NewWebview(settings Settings) WebView {
|
||||
if settings.Width == 0 {
|
||||
settings.Width = 640
|
||||
}
|
||||
if settings.Height == 0 {
|
||||
settings.Height = 480
|
||||
}
|
||||
if settings.Title == "" {
|
||||
settings.Title = "WebView"
|
||||
}
|
||||
w := &webview{}
|
||||
w.w = C.CgoWebViewCreate(C.int(settings.Width), C.int(settings.Height),
|
||||
C.CString(settings.Title), C.CString(settings.URL),
|
||||
C.int(boolToInt(settings.Resizable)), C.int(boolToInt(settings.Debug)))
|
||||
m.Lock()
|
||||
if settings.ExternalInvokeCallback != nil {
|
||||
cbs[w] = settings.ExternalInvokeCallback
|
||||
} else {
|
||||
cbs[w] = func(w WebView, data string) {}
|
||||
}
|
||||
m.Unlock()
|
||||
return w
|
||||
}
|
||||
|
||||
func (w *webview) Loop(blocking bool) bool {
|
||||
block := C.int(0)
|
||||
if blocking {
|
||||
block = 1
|
||||
}
|
||||
return C.CgoWebViewLoop(w.w, block) == 0
|
||||
}
|
||||
|
||||
func (w *webview) Run() {
|
||||
for w.Loop(true) {
|
||||
}
|
||||
}
|
||||
|
||||
func (w *webview) Exit() {
|
||||
C.CgoWebViewExit(w.w)
|
||||
}
|
||||
|
||||
func (w *webview) Dispatch(f func()) {
|
||||
m.Lock()
|
||||
for ; fns[index] != nil; index++ {
|
||||
}
|
||||
fns[index] = f
|
||||
m.Unlock()
|
||||
C.CgoWebViewDispatch(w.w, C.uintptr_t(index))
|
||||
}
|
||||
|
||||
func (w *webview) SetTitle(title string) {
|
||||
p := C.CString(title)
|
||||
defer C.free(unsafe.Pointer(p))
|
||||
C.CgoWebViewSetTitle(w.w, p)
|
||||
}
|
||||
|
||||
func (w *webview) SetColor(r, g, b, a uint8) {
|
||||
C.CgoWebViewSetColor(w.w, C.uint8_t(r), C.uint8_t(g), C.uint8_t(b), C.uint8_t(a))
|
||||
}
|
||||
|
||||
func (w *webview) SetFullscreen(fullscreen bool) {
|
||||
C.CgoWebViewSetFullscreen(w.w, C.int(boolToInt(fullscreen)))
|
||||
}
|
||||
|
||||
func (w *webview) Dialog(dlgType DialogType, flags int, title string, arg string) string {
|
||||
const maxPath = 4096
|
||||
titlePtr := C.CString(title)
|
||||
defer C.free(unsafe.Pointer(titlePtr))
|
||||
argPtr := C.CString(arg)
|
||||
defer C.free(unsafe.Pointer(argPtr))
|
||||
resultPtr := (*C.char)(C.calloc((C.size_t)(unsafe.Sizeof((*C.char)(nil))), (C.size_t)(maxPath)))
|
||||
defer C.free(unsafe.Pointer(resultPtr))
|
||||
C.CgoDialog(w.w, C.int(dlgType), C.int(flags), titlePtr,
|
||||
argPtr, resultPtr, C.size_t(maxPath))
|
||||
return C.GoString(resultPtr)
|
||||
}
|
||||
|
||||
func (w *webview) Eval(js string) error {
|
||||
p := C.CString(js)
|
||||
defer C.free(unsafe.Pointer(p))
|
||||
switch C.CgoWebViewEval(w.w, p) {
|
||||
case -1:
|
||||
return errors.New("evaluation failed")
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
func (w *webview) InjectCSS(css string) {
|
||||
p := C.CString(css)
|
||||
defer C.free(unsafe.Pointer(p))
|
||||
C.CgoWebViewInjectCSS(w.w, p)
|
||||
}
|
||||
|
||||
func (w *webview) Terminate() {
|
||||
C.CgoWebViewTerminate(w.w)
|
||||
}
|
||||
|
||||
//export _webviewDispatchGoCallback
|
||||
func _webviewDispatchGoCallback(index unsafe.Pointer) {
|
||||
var f func()
|
||||
m.Lock()
|
||||
f = fns[uintptr(index)]
|
||||
delete(fns, uintptr(index))
|
||||
m.Unlock()
|
||||
f()
|
||||
}
|
||||
|
||||
//export _webviewExternalInvokeCallback
|
||||
func _webviewExternalInvokeCallback(w unsafe.Pointer, data unsafe.Pointer) {
|
||||
m.Lock()
|
||||
var (
|
||||
cb ExternalInvokeCallbackFunc
|
||||
wv WebView
|
||||
)
|
||||
for wv, cb = range cbs {
|
||||
if wv.(*webview).w == w {
|
||||
break
|
||||
}
|
||||
}
|
||||
m.Unlock()
|
||||
cb(wv, C.GoString((*C.char)(data)))
|
||||
}
|
||||
1927
webview/webview.h
1927
webview/webview.h
File diff suppressed because it is too large
Load Diff
Reference in New Issue
Block a user