Compare commits

...

34 Commits

Author SHA1 Message Date
Lea Anthony
b5b78fddee move webview out to seperate project 2019-02-11 08:28:07 +11:00
Lea Anthony
c905185467 Merge pull request #42 from wailsapp/improve-build-output
Reduce output of prod build by ~30%
2019-02-06 06:27:38 +11:00
Lea Anthony
47ca7879cd Reduce output of prod build by ~30% 2019-02-06 06:26:54 +11:00
Lea Anthony
6202b3bf3e Merge pull request #41 from wailsapp/fix-linting-issues
simplified PromptForInputs
2019-02-05 18:53:32 +11:00
Lea Anthony
ea94c2de1f simplified PromptForInputs 2019-02-05 18:51:08 +11:00
Lea Anthony
eb0d4bc42f Merge pull request #40 from wailsapp/fix-linting-issues
Fix linting issues
2019-02-05 08:45:08 +11:00
Lea Anthony
b323c3db20 refactor promptforinputs 2019-02-05 08:43:50 +11:00
Lea Anthony
1670ac6567 add comments 2019-02-05 08:11:02 +11:00
Lea Anthony
c941176018 simplify Serve 2019-02-05 08:06:18 +11:00
Lea Anthony
a060d9dcc0 fix bridge installation path 2019-02-05 08:03:07 +11:00
Lea Anthony
ba208dce44 Merge pull request #39 from wailsapp/fix-linting-issues
Fix linting issues
2019-02-04 21:10:46 +11:00
Lea Anthony
9bbac46b3f Misc refactors 2019-02-04 21:09:56 +11:00
Lea Anthony
d8c591e64c refactored processCall 2019-02-04 19:50:26 +11:00
Lea Anthony
2c28a8f550 Fix css 2019-02-04 19:31:37 +11:00
Lea Anthony
d6c5586159 Merge pull request #38 from wailsapp/Improve-build/serve
Improve build/serve
2019-02-04 19:27:12 +11:00
Lea Anthony
08a7893b1d refactored build/serve 2019-02-04 18:49:56 +11:00
Lea Anthony
fa6cf17079 Fixed wails serve. Improved code structure. 2019-02-04 08:45:12 +11:00
Lea Anthony
fe2a20f92a Merge pull request #36 from wailsapp/Improve-build/serve
Improve build/serve
2019-02-02 14:07:14 +11:00
Lea Anthony
b713d57168 Tidy up serve. 2019-02-02 13:58:55 +11:00
Lea Anthony
17ca06693e add debug mode to build 2019-02-02 09:29:14 +11:00
Lea Anthony
243d738d64 Merge pull request #35 from wailsapp/Make-Serve-command
Add helpful message after serving
2019-01-31 18:59:37 +11:00
Lea Anthony
3f50b95f26 Add helpful message after serving 2019-01-31 18:59:07 +11:00
Lea Anthony
f0d8ce99a1 Merge pull request #34 from wailsapp/Make-Serve-command
Make serve command
2019-01-31 18:49:18 +11:00
Lea Anthony
259eec97d6 Added serve.
Serve only builds backend.
Build is always release build.
2019-01-31 18:48:12 +11:00
Lea Anthony
8b2168abe7 upgraded spinner to 0.5.0 2019-01-31 18:47:27 +11:00
Lea Anthony
a51e127309 Merge pull request #32 from wailsapp/Massively-Simplify
add webview license
2019-01-30 20:28:49 +11:00
Lea Anthony
c5cee79ff7 add webview license 2019-01-30 20:28:21 +11:00
Lea Anthony
9393b08c3f Merge pull request #31 from wailsapp/Massively-Simplify
Initial commit of simplification
2019-01-30 19:05:52 +11:00
Lea Anthony
0ca039e914 Initial commit of simplification 2019-01-30 09:00:46 +11:00
Lea Anthony
cd8b4f088f Merge pull request #29 from wailsapp/Move-headless-capability-into-own-library
Move headless capability into own library
2019-01-29 08:37:33 +11:00
Lea Anthony
847842504b Merge branch 'master' into Move-headless-capability-into-own-library 2019-01-29 08:36:27 +11:00
Lea Anthony
8ab91d31fe reduce function complexity 2019-01-29 08:36:21 +11:00
Lea Anthony
bb4d891549 Merge pull request #28 from wailsapp/Create-consistent-templates
Updated custom html
2019-01-29 08:31:21 +11:00
Lea Anthony
529e4cc07e Merge pull request #27 from wailsapp/Create-consistent-templates
update basic templates to use a frontend dir
2019-01-29 08:29:40 +11:00
56 changed files with 776 additions and 3762 deletions

File diff suppressed because one or more lines are too long

17
app.go
View File

@@ -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)

View File

@@ -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

View File

@@ -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();
}
};

View File

@@ -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();
}
};

File diff suppressed because one or more lines are too long

View File

@@ -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;
}

View File

@@ -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();
}
}
};

View File

@@ -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>

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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

View File

@@ -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"),
}
}

View File

@@ -1,5 +0,0 @@
{
"Name": "Bootstrap 4",
"Description": "Standard Bootstrap 4 with default theme",
"BuildTag": "frameworkbootstrap4"
}

View File

@@ -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

View File

@@ -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

View File

@@ -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"),
}
}

View File

@@ -1,5 +0,0 @@
{
"Name": "Bootstrap 4 (Lux)",
"Description": "Bootstrap with Lux theme",
"BuildTag": "frameworkbootstrap4lux"
}

View File

@@ -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
View 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
}

View File

@@ -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)

View File

@@ -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
}

View File

@@ -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>

View File

@@ -1 +0,0 @@
module {{.BinaryName}}

View File

@@ -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()
}

View File

@@ -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"
}

View File

@@ -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>

View File

@@ -1 +0,0 @@
module {{.BinaryName}}

View File

@@ -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()
}

View File

@@ -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"
}

View File

@@ -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 */
}

View File

@@ -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;
}
}

View File

@@ -25,7 +25,11 @@ export default {
}
},
created() {
if( !backend ) {
eventBus.$on("ready", this.getNewQuote);
} else {
this.getNewQuote();
}
}
};
</script>

View File

@@ -7,8 +7,7 @@ new Vue({
}).$mount("#app");
import Bridge from "./wailsbridge";
Bridge.Start(startApp);
function startApp() {
Bridge.OnReady(() => {
eventBus.$emit("ready");
}
});
Bridge.Start();

View File

@@ -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"
}

View File

@@ -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"

View File

@@ -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
}

View File

@@ -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
View 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
View 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
View File

@@ -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
View File

@@ -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=

View File

@@ -13,7 +13,6 @@ type Renderer interface {
NotifyEvent(eventData *eventData) error
// Injection
InjectFramework(js string, css string)
AddJSList(js []string)
AddCSSList(css []string)

View File

@@ -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 {

View File

@@ -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

View File

@@ -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)))
}

File diff suppressed because it is too large Load Diff