Fenster eingebaut
This commit is contained in:
parent
f7a24eb969
commit
830411664c
|
@ -12,7 +12,7 @@ TODO::
|
|||
* ~~Logout~~
|
||||
* Konfis auf der Frontseite mit Websockets updaten
|
||||
* ~~Mode hinzufügen: in der Config soll man zwischen Gemeinden und Konfis umschalten können, so dass entweder die Gemeinden oder Konfis gegeneinander spielen~~
|
||||
* Alles in Fenster packen
|
||||
* ~~Alles in Fenster packen~~
|
||||
* Alles an schriften/Bildern/Etc Herunterladen, damit alles auch offline funktioniert
|
||||
* ~~Random Port (wenn man irgendwie den laufenden port finden kann)~~
|
||||
* ~~Front-Tabelle schöner~~
|
||||
|
@ -20,3 +20,8 @@ TODO::
|
|||
* Mini-Doku
|
||||
* Inbetriebnahme
|
||||
* Bedienung
|
||||
|
||||
Release: 3 Zips. Enthalten jeweils die kompilierten binaries, Templates, JS/CSS/Fonts/etc. Sozusagen Ready-to-Run.
|
||||
* Win
|
||||
* macOS
|
||||
* Linux
|
|
@ -1,26 +1,29 @@
|
|||
$(document).ready(function () {
|
||||
$('#loginform').submit(function (ev) {
|
||||
ev.preventDefault();
|
||||
console.log('sumbit');
|
||||
var pass = $('#password').val();
|
||||
if(pass == ""){
|
||||
$('#msg').html('<div class="ui error message" style="display: block;">Bitte gib ein Passwort ein.</div>');
|
||||
} else {
|
||||
$.ajax({
|
||||
url: '/login',
|
||||
method: 'POST',
|
||||
data: 'password=' + pass,
|
||||
success: function (msg) {
|
||||
console.log(msg);
|
||||
if(msg.Message == 'success') {
|
||||
$('#msg').html('<div class="ui success message" style="display: block;">Erfolgreich eingeloggt.</div>');
|
||||
location.reload();
|
||||
} else {
|
||||
$('#msg').html('<div class="ui error message" style="display: block;">Falsches Passwort.</div>');
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
login();
|
||||
});
|
||||
});
|
||||
|
||||
function login() {
|
||||
console.log('sumbit');
|
||||
var pass = $('#password').val();
|
||||
if(pass == ""){
|
||||
$('#msg').html('<div class="ui error message" style="display: block;">Bitte gib ein Passwort ein.</div>');
|
||||
} else {
|
||||
$.ajax({
|
||||
url: '/login',
|
||||
method: 'POST',
|
||||
data: 'password=' + pass,
|
||||
success: function (msg) {
|
||||
console.log(msg);
|
||||
if(msg.Message == 'success') {
|
||||
$('#msg').html('<div class="ui success message" style="display: block;">Erfolgreich eingeloggt.</div>');
|
||||
location.reload();
|
||||
} else {
|
||||
$('#msg').html('<div class="ui error message" style="display: block;">Falsches Passwort.</div>');
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
BIN
astilectron-deps/vendor/astilectron-v0.6.0.zip
vendored
Normal file
BIN
astilectron-deps/vendor/astilectron-v0.6.0.zip
vendored
Normal file
Binary file not shown.
4
astilectron-deps/vendor/astilectron/.gitignore
vendored
Normal file
4
astilectron-deps/vendor/astilectron/.gitignore
vendored
Normal file
|
@ -0,0 +1,4 @@
|
|||
.idea/
|
||||
node_modules
|
||||
npm-debug.log
|
||||
dist
|
21
astilectron-deps/vendor/astilectron/LICENSE
vendored
Normal file
21
astilectron-deps/vendor/astilectron/LICENSE
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Quentin RENARD
|
||||
|
||||
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.
|
277
astilectron-deps/vendor/astilectron/main.js
vendored
Normal file
277
astilectron-deps/vendor/astilectron/main.js
vendored
Normal file
|
@ -0,0 +1,277 @@
|
|||
'use strict'
|
||||
|
||||
const electron = require('electron')
|
||||
const {app, BrowserWindow, ipcMain, Menu, MenuItem, Tray} = electron
|
||||
const consts = require('./src/consts.js')
|
||||
const client = require('./src/client.js').init()
|
||||
const rl = require('readline').createInterface({input: client.socket})
|
||||
|
||||
let elements = {}
|
||||
let menus = {}
|
||||
|
||||
// App is ready
|
||||
app.on('ready',() => {
|
||||
// Init
|
||||
const screen = electron.screen
|
||||
Menu.setApplicationMenu(null)
|
||||
|
||||
// Listen to screen events
|
||||
screen.on('display-added', function() {
|
||||
client.write(consts.mainTargetID, consts.eventNames.displayEventAdded, {displays: {all: screen.getAllDisplays(), primary: screen.getPrimaryDisplay()}})
|
||||
})
|
||||
screen.on('display-metrics-changed', function() {
|
||||
client.write(consts.mainTargetID, consts.eventNames.displayEventMetricsChanged, {displays: {all: screen.getAllDisplays(), primary: screen.getPrimaryDisplay()}})
|
||||
})
|
||||
screen.on('display-removed', function() {
|
||||
client.write(consts.mainTargetID, consts.eventNames.displayEventRemoved, {displays: {all: screen.getAllDisplays(), primary: screen.getPrimaryDisplay()}})
|
||||
})
|
||||
|
||||
// Listen on main ipcMain
|
||||
ipcMain.on(consts.eventNames.ipcWindowMessage, (event, arg) => {
|
||||
client.write(arg.targetID, consts.eventNames.windowEventMessage, {message: arg.message})
|
||||
})
|
||||
|
||||
// Read from client
|
||||
rl.on('line', function(line){
|
||||
// Parse the JSON
|
||||
var json = JSON.parse(line)
|
||||
|
||||
// Switch on event name
|
||||
switch (json.name) {
|
||||
// Menu
|
||||
case consts.eventNames.menuCmdCreate:
|
||||
menuCreate(json.menu)
|
||||
menus[json.menu.rootId] = json.targetID
|
||||
setMenu(json.menu.rootId)
|
||||
client.write(json.targetID, consts.eventNames.menuEventCreated)
|
||||
break;
|
||||
case consts.eventNames.menuCmdDestroy:
|
||||
elements[json.targetID] = null
|
||||
if (menus[json.menu.rootId] == json.targetID) {
|
||||
menus[json.menu.rootId] = null
|
||||
setMenu(json.menu.rootId)
|
||||
}
|
||||
client.write(json.targetID, consts.eventNames.menuEventDestroyed)
|
||||
break;
|
||||
|
||||
// Menu item
|
||||
case consts.eventNames.menuItemCmdSetChecked:
|
||||
elements[json.targetID].checked = json.menuItemOptions.checked
|
||||
client.write(json.targetID, consts.eventNames.menuItemEventCheckedSet)
|
||||
break;
|
||||
case consts.eventNames.menuItemCmdSetEnabled:
|
||||
elements[json.targetID].enabled = json.menuItemOptions.enabled
|
||||
client.write(json.targetID, consts.eventNames.menuItemEventEnabledSet)
|
||||
break;
|
||||
case consts.eventNames.menuItemCmdSetLabel:
|
||||
elements[json.targetID].label = json.menuItemOptions.label
|
||||
client.write(json.targetID, consts.eventNames.menuItemEventLabelSet)
|
||||
break;
|
||||
case consts.eventNames.menuItemCmdSetVisible:
|
||||
elements[json.targetID].visible = json.menuItemOptions.visible
|
||||
client.write(json.targetID, consts.eventNames.menuItemEventVisibleSet)
|
||||
break;
|
||||
|
||||
// Sub menu
|
||||
case consts.eventNames.subMenuCmdAppend:
|
||||
elements[json.targetID].append(menuItemCreate(json.menuItem))
|
||||
setMenu(json.menuItem.rootId)
|
||||
client.write(json.targetID, consts.eventNames.subMenuEventAppended)
|
||||
break;
|
||||
case consts.eventNames.subMenuCmdClosePopup:
|
||||
var window = null
|
||||
if (typeof json.windowId !== "undefined") {
|
||||
window = elements[json.windowId]
|
||||
}
|
||||
elements[json.targetID].closePopup(window)
|
||||
client.write(json.targetID, consts.eventNames.subMenuEventClosedPopup)
|
||||
break;
|
||||
case consts.eventNames.subMenuCmdInsert:
|
||||
elements[json.targetID].insert(json.menuItemPosition, menuItemCreate(json.menuItem))
|
||||
setMenu(json.menuItem.rootId)
|
||||
client.write(json.targetID, consts.eventNames.subMenuEventInserted)
|
||||
break;
|
||||
case consts.eventNames.subMenuCmdPopup:
|
||||
var window = null
|
||||
if (typeof json.windowId !== "undefined") {
|
||||
window = elements[json.windowId]
|
||||
}
|
||||
json.menuPopupOptions.async = true
|
||||
elements[json.targetID].popup(window, json.menuPopupOptions)
|
||||
client.write(json.targetID, consts.eventNames.subMenuEventPoppedUp)
|
||||
break;
|
||||
|
||||
// Tray
|
||||
case consts.eventNames.trayCmdCreate:
|
||||
elements[json.targetID] = new Tray(json.trayOptions.image)
|
||||
if (typeof json.menuId !== "undefined") {
|
||||
elements[json.targetID].setContextMenu(elements[json.menuId]);
|
||||
}
|
||||
if (typeof json.trayOptions.tooltip !== "undefined") {
|
||||
elements[json.targetID].setToolTip(json.trayOptions.tooltip);
|
||||
}
|
||||
client.write(json.targetID, consts.eventNames.trayEventCreated)
|
||||
break;
|
||||
case consts.eventNames.trayCmdDestroy:
|
||||
elements[json.targetID].destroy()
|
||||
elements[json.targetID] = null
|
||||
client.write(json.targetID, consts.eventNames.trayEventDestroyed)
|
||||
break;
|
||||
|
||||
// Window
|
||||
case consts.eventNames.windowCmdBlur:
|
||||
elements[json.targetID].blur()
|
||||
break;
|
||||
case consts.eventNames.windowCmdCenter:
|
||||
elements[json.targetID].center()
|
||||
break;
|
||||
case consts.eventNames.windowCmdClose:
|
||||
elements[json.targetID].close()
|
||||
break;
|
||||
case consts.eventNames.windowCmdCreate:
|
||||
windowCreate(json)
|
||||
break;
|
||||
case consts.eventNames.windowCmdDestroy:
|
||||
elements[json.targetID].destroy()
|
||||
elements[json.targetID] = null
|
||||
break;
|
||||
case consts.eventNames.windowCmdFocus:
|
||||
elements[json.targetID].focus()
|
||||
break;
|
||||
case consts.eventNames.windowCmdHide:
|
||||
elements[json.targetID].hide()
|
||||
break;
|
||||
case consts.eventNames.windowCmdMaximize:
|
||||
elements[json.targetID].maximize()
|
||||
break;
|
||||
case consts.eventNames.windowCmdMessage:
|
||||
elements[json.targetID].webContents.send(consts.eventNames.ipcWindowMessage, json.message)
|
||||
break;
|
||||
case consts.eventNames.windowCmdMinimize:
|
||||
elements[json.targetID].minimize()
|
||||
break;
|
||||
case consts.eventNames.windowCmdMove:
|
||||
elements[json.targetID].setPosition(json.windowOptions.x, json.windowOptions.y, true)
|
||||
break;
|
||||
case consts.eventNames.windowCmdResize:
|
||||
elements[json.targetID].setSize(json.windowOptions.width, json.windowOptions.height, true)
|
||||
break;
|
||||
case consts.eventNames.windowCmdRestore:
|
||||
elements[json.targetID].restore()
|
||||
break;
|
||||
case consts.eventNames.windowCmdShow:
|
||||
elements[json.targetID].show()
|
||||
break;
|
||||
case consts.eventNames.windowCmdWebContentsCloseDevTools:
|
||||
elements[json.targetID].webContents.closeDevTools()
|
||||
break;
|
||||
case consts.eventNames.windowCmdWebContentsOpenDevTools:
|
||||
elements[json.targetID].webContents.openDevTools()
|
||||
break;
|
||||
case consts.eventNames.windowCmdUnmaximize:
|
||||
elements[json.targetID].unmaximize()
|
||||
break;
|
||||
}
|
||||
})
|
||||
|
||||
// Send electron.ready event
|
||||
client.write(consts.mainTargetID, consts.eventNames.appEventReady, {displays: {all: screen.getAllDisplays(), primary: screen.getPrimaryDisplay()}})
|
||||
})
|
||||
|
||||
// menuCreate creates a new menu
|
||||
function menuCreate(menu) {
|
||||
if (typeof menu !== "undefined") {
|
||||
elements[menu.id] = new Menu()
|
||||
for(var i = 0; i < menu.items.length; i++) {
|
||||
elements[menu.id].append(menuItemCreate(menu.items[i]))
|
||||
}
|
||||
return elements[menu.id]
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
// menuItemCreate creates a menu item
|
||||
function menuItemCreate(menuItem) {
|
||||
const itemId = menuItem.id
|
||||
menuItem.options.click = function(menuItem) {
|
||||
client.write(itemId, consts.eventNames.menuItemEventClicked, {menuItemOptions: menuItemToJSON(menuItem)})
|
||||
}
|
||||
if (typeof menuItem.submenu !== "undefined") {
|
||||
menuItem.options.type = 'submenu'
|
||||
menuItem.options.submenu = menuCreate(menuItem.submenu)
|
||||
}
|
||||
elements[itemId] = new MenuItem(menuItem.options)
|
||||
return elements[itemId]
|
||||
}
|
||||
|
||||
// menuItemToJSON returns the proper fields not to raise an exception
|
||||
function menuItemToJSON(menuItem) {
|
||||
return {
|
||||
checked: menuItem.checked,
|
||||
enabled: menuItem.enabled,
|
||||
label: menuItem.label,
|
||||
visible: menuItem.visible,
|
||||
}
|
||||
}
|
||||
|
||||
// setMenu sets a menu
|
||||
function setMenu(rootId) {
|
||||
var menu = null
|
||||
if (typeof menus[rootId] !== "undefined" && typeof elements[menus[rootId]] !== "undefined") {
|
||||
menu = elements[menus[rootId]]
|
||||
}
|
||||
rootId == consts.mainTargetID ? Menu.setApplicationMenu(menu) : elements[rootId].setMenu(menu)
|
||||
}
|
||||
|
||||
// windowCreate creates a new window
|
||||
function windowCreate(json) {
|
||||
elements[json.targetID] = new BrowserWindow(json.windowOptions)
|
||||
elements[json.targetID].setMenu(null)
|
||||
elements[json.targetID].loadURL(json.url);
|
||||
elements[json.targetID].on('blur', () => { client.write(json.targetID, consts.eventNames.windowEventBlur) })
|
||||
elements[json.targetID].on('closed', () => {
|
||||
client.write(json.targetID, consts.eventNames.windowEventClosed)
|
||||
delete elements[json.targetID]
|
||||
})
|
||||
elements[json.targetID].on('focus', () => { client.write(json.targetID, consts.eventNames.windowEventFocus) })
|
||||
elements[json.targetID].on('hide', () => { client.write(json.targetID, consts.eventNames.windowEventHide) })
|
||||
elements[json.targetID].on('maximize', () => { client.write(json.targetID, consts.eventNames.windowEventMaximize) })
|
||||
elements[json.targetID].on('minimize', () => { client.write(json.targetID, consts.eventNames.windowEventMinimize) })
|
||||
elements[json.targetID].on('move', () => { client.write(json.targetID, consts.eventNames.windowEventMove) })
|
||||
elements[json.targetID].on('ready-to-show', () => { client.write(json.targetID, consts.eventNames.windowEventReadyToShow) })
|
||||
elements[json.targetID].on('resize', () => { client.write(json.targetID, consts.eventNames.windowEventResize) })
|
||||
elements[json.targetID].on('restore', () => { client.write(json.targetID, consts.eventNames.windowEventRestore) })
|
||||
elements[json.targetID].on('show', () => { client.write(json.targetID, consts.eventNames.windowEventShow) })
|
||||
elements[json.targetID].on('unmaximize', () => { client.write(json.targetID, consts.eventNames.windowEventUnmaximize) })
|
||||
elements[json.targetID].on('unresponsive', () => { client.write(json.targetID, consts.eventNames.windowEventUnresponsive) })
|
||||
elements[json.targetID].webContents.on('did-finish-load', () => {
|
||||
elements[json.targetID].webContents.executeJavaScript(
|
||||
`const {ipcRenderer} = require('electron')
|
||||
const {dialog} = require('electron').remote
|
||||
var astilectron = {
|
||||
listen: function(callback) {
|
||||
ipcRenderer.on('`+ consts.eventNames.ipcWindowMessage +`', function(event, message) {
|
||||
callback(message)
|
||||
})
|
||||
},
|
||||
send: function(message) {
|
||||
ipcRenderer.send('`+ consts.eventNames.ipcWindowMessage +`', {message: message, targetID: '`+ json.targetID +`'})
|
||||
},
|
||||
showErrorBox: function(title, content) {
|
||||
dialog.showErrorBox(title, content)
|
||||
},
|
||||
showMessageBox: function(options, callback) {
|
||||
dialog.showMessageBox(null, options, callback)
|
||||
},
|
||||
showOpenDialog: function(options, callback) {
|
||||
dialog.showOpenDialog(null, options, callback)
|
||||
},
|
||||
showSaveDialog: function(options, callback) {
|
||||
dialog.showSaveDialog(null, options, callback)
|
||||
}
|
||||
}
|
||||
document.dispatchEvent(new Event('astilectron-ready'))`
|
||||
)
|
||||
client.write(json.targetID, consts.eventNames.windowEventDidFinishLoad)
|
||||
})
|
||||
}
|
7
astilectron-deps/vendor/astilectron/package.json
vendored
Normal file
7
astilectron-deps/vendor/astilectron/package.json
vendored
Normal file
|
@ -0,0 +1,7 @@
|
|||
{
|
||||
"name": "Astilectron",
|
||||
"description": "Electron-based cross-language application framework",
|
||||
"devDependencies": {
|
||||
"electron": "1.6.5"
|
||||
}
|
||||
}
|
61
astilectron-deps/vendor/astilectron/readme.md
vendored
Normal file
61
astilectron-deps/vendor/astilectron/readme.md
vendored
Normal file
|
@ -0,0 +1,61 @@
|
|||
`astilectron` is an Electron app that provides an API over a TCP socket that allows executing Electron's method as well as capturing Electron's events.
|
||||
|
||||
# Architecture
|
||||
|
||||
+-----------------------+ TCP +-------------+ IPC +---------------------+
|
||||
+ Client App (any Lang) |<--------->+ Astilectron +<-------->+ win1: (HTML/JS/CSS) +
|
||||
+-----------------------+ +-------------+ | +---------------------++
|
||||
| | +---->+ win2: (HTML/JS/CSS) +
|
||||
| +----------+ | | +---------------------++
|
||||
+---------+ Electron +--------+ +-->+ win3: (HTML/JS/CSS) +
|
||||
+----------+ +---------------------+
|
||||
|
||||
# Language bindings
|
||||
|
||||
Language bindings play a major role with `astilectron` as they allow communicating with its TCP socket and therefore interacting with its API in any language.
|
||||
|
||||
## I want to develop language bindings for a new language
|
||||
|
||||
Great! :)
|
||||
|
||||
Here's a few things you need to know:
|
||||
|
||||
- it's the responsibility of the language bindings to provision `astilectron` which usually consists of downloading and unzipping `astilectron` as well as `electron`
|
||||
- the TCP addr is sent to `astilectron` through a command line argument therefore your command line when calling `astilectron` should look like `<path to electron executable> <path to astilectron directory>/main.js <tcp addr>`
|
||||
|
||||
## Language bindings for GO
|
||||
|
||||
Check out [go-astilectron](https://github.com/asticode/go-astilectron) for `astilectron` GO language bindings
|
||||
|
||||
# Features and roadmap
|
||||
|
||||
- [x] window basic methods (create, show, close, resize, minimize, maximize, ...)
|
||||
- [x] window basic events (close, blur, focus, unresponsive, crashed, ...)
|
||||
- [x] remote messaging (messages between GO and the JS in the webserver)
|
||||
- [x] multi screens/displays
|
||||
- [x] menu methods and events (create, insert, append, popup, clicked, ...)
|
||||
- [x] dialogs (open or save file, alerts, ...)
|
||||
- [ ] accelerators (shortcuts)
|
||||
- [ ] file methods (drag & drop, ...)
|
||||
- [ ] clipboard methods
|
||||
- [ ] power monitor events (suspend, resume, ...)
|
||||
- [ ] notifications (macosx)
|
||||
- [ ] desktop capturer (audio and video)
|
||||
- [ ] session methods
|
||||
- [ ] session events
|
||||
- [ ] window advanced options (add missing ones)
|
||||
- [ ] window advanced methods (add missing ones)
|
||||
- [ ] window advanced events (add missing ones)
|
||||
- [ ] child windows
|
||||
|
||||
# Contribute
|
||||
|
||||
For now only GO has its official bindings with `astilectron`, but the more language has its bindings the better! Therefore if you feel like implementing bindings with `astilectron` in some other language feel free to reach out to me to get some more info and finally to get your repo listed here.
|
||||
|
||||
Also I'm far from being an expert in Node.JS therefore if you see anything that seems wrong in `astilectron` feel free to create an issue or even better contribute through a PR!
|
||||
|
||||
You know you want to! :D
|
||||
|
||||
# Cheers to
|
||||
|
||||
[thrust](https://github.com/breach/thrust) which is awesome but unfortunately not maintained anymore. It inspired this project.
|
27
astilectron-deps/vendor/astilectron/src/client.js
vendored
Normal file
27
astilectron-deps/vendor/astilectron/src/client.js
vendored
Normal file
|
@ -0,0 +1,27 @@
|
|||
'use strict'
|
||||
|
||||
const net = require('net');
|
||||
const url = require('url');
|
||||
|
||||
// Client can read/write messages from a TCP server
|
||||
class Client {
|
||||
// init initializes the Client
|
||||
init() {
|
||||
var u = url.parse("tcp://" + process.argv[2], false, false)
|
||||
this.socket = new net.Socket()
|
||||
this.socket.connect(u.port, u.hostname, function() {});
|
||||
this.socket.on('close', function() {
|
||||
process.exit()
|
||||
})
|
||||
return this
|
||||
}
|
||||
|
||||
// write writes an event to the server
|
||||
write(targetID, eventName, payload) {
|
||||
var data = {name: eventName, targetID: targetID}
|
||||
if (typeof payload != "undefined") Object.assign(data, payload)
|
||||
this.socket.write(JSON.stringify(data) + "\n")
|
||||
}
|
||||
}
|
||||
|
||||
module.exports = new Client()
|
69
astilectron-deps/vendor/astilectron/src/consts.js
vendored
Normal file
69
astilectron-deps/vendor/astilectron/src/consts.js
vendored
Normal file
|
@ -0,0 +1,69 @@
|
|||
'use strict'
|
||||
|
||||
module.exports = {
|
||||
eventNames: {
|
||||
appEventReady: "app.event.ready",
|
||||
displayEventAdded: "display.event.added",
|
||||
displayEventMetricsChanged: "display.event.metrics.changed",
|
||||
displayEventRemoved: "display.event.removed",
|
||||
ipcWindowMessage: "ipc.window.message",
|
||||
menuCmdCreate: "menu.cmd.create",
|
||||
menuCmdDestroy: "menu.cmd.destroy",
|
||||
menuEventCreated: "menu.event.created",
|
||||
menuEventDestroyed: "menu.event.destroyed",
|
||||
menuItemCmdSetChecked: "menu.item.cmd.set.checked",
|
||||
menuItemCmdSetEnabled: "menu.item.cmd.set.enabled",
|
||||
menuItemCmdSetLabel: "menu.item.cmd.set.label",
|
||||
menuItemCmdSetVisible: "menu.item.cmd.set.visible",
|
||||
menuItemEventCheckedSet: "menu.item.event.checked.set",
|
||||
menuItemEventClicked: "menu.item.event.clicked",
|
||||
menuItemEventEnabledSet: "menu.item.event.enabled.set",
|
||||
menuItemEventLabelSet: "menu.item.event.label.set",
|
||||
menuItemEventVisibleSet: "menu.item.event.visible.set",
|
||||
subMenuCmdAppend: "sub.menu.cmd.append",
|
||||
subMenuCmdClosePopup: "sub.menu.cmd.close.popup",
|
||||
subMenuCmdInsert: "sub.menu.cmd.insert",
|
||||
subMenuCmdPopup: "sub.menu.cmd.popup",
|
||||
subMenuEventAppended: "sub.menu.event.appended",
|
||||
subMenuEventClosedPopup: "sub.menu.event.closed.popup",
|
||||
subMenuEventInserted: "sub.menu.event.inserted",
|
||||
subMenuEventPoppedUp: "sub.menu.event.popped.up",
|
||||
trayCmdCreate: "tray.cmd.create",
|
||||
trayCmdDestroy: "tray.cmd.destroy",
|
||||
trayEventCreated: "tray.event.created",
|
||||
trayEventDestroyed: "tray.event.destroyed",
|
||||
windowCmdBlur: "window.cmd.blur",
|
||||
windowCmdCenter: "window.cmd.center",
|
||||
windowCmdClose: "window.cmd.close",
|
||||
windowCmdCreate: "window.cmd.create",
|
||||
windowCmdDestroy: "window.cmd.destroy",
|
||||
windowCmdFocus: "window.cmd.focus",
|
||||
windowCmdHide: "window.cmd.hide",
|
||||
windowCmdMaximize: "window.cmd.maximize",
|
||||
windowCmdMessage: "window.cmd.message",
|
||||
windowCmdMinimize: "window.cmd.minimize",
|
||||
windowCmdMove: "window.cmd.move",
|
||||
windowCmdResize: "window.cmd.resize",
|
||||
windowCmdRestore: "window.cmd.restore",
|
||||
windowCmdShow: "window.cmd.show",
|
||||
windowCmdUnmaximize: "window.cmd.unmaximize",
|
||||
windowCmdWebContentsCloseDevTools: "window.cmd.web.contents.close.dev.tools",
|
||||
windowCmdWebContentsOpenDevTools: "window.cmd.web.contents.open.dev.tools",
|
||||
windowEventBlur: "window.event.blur",
|
||||
windowEventClosed: "window.event.closed",
|
||||
windowEventDidFinishLoad: "window.event.did.finish.load",
|
||||
windowEventFocus: "window.event.focus",
|
||||
windowEventHide: "window.event.hide",
|
||||
windowEventMaximize: "window.event.maximize",
|
||||
windowEventMessage: "window.event.message",
|
||||
windowEventMinimize: "window.event.minimize",
|
||||
windowEventMove: "window.event.move",
|
||||
windowEventReadyToShow: "window.event.ready.to.show",
|
||||
windowEventResize: "window.event.resize",
|
||||
windowEventRestore: "window.event.restore",
|
||||
windowEventShow: "window.event.show",
|
||||
windowEventUnmaximize: "window.event.unmaximize",
|
||||
windowEventUnresponsive: "window.event.unresponsive",
|
||||
},
|
||||
mainTargetID: 'main'
|
||||
}
|
BIN
astilectron-deps/vendor/electron-v1.6.5.zip
vendored
Normal file
BIN
astilectron-deps/vendor/electron-v1.6.5.zip
vendored
Normal file
Binary file not shown.
20
astilectron-deps/vendor/electron/LICENSE
vendored
Normal file
20
astilectron-deps/vendor/electron/LICENSE
vendored
Normal file
|
@ -0,0 +1,20 @@
|
|||
Copyright (c) 2013-2017 GitHub Inc.
|
||||
|
||||
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.
|
33911
astilectron-deps/vendor/electron/LICENSES.chromium.html
vendored
Normal file
33911
astilectron-deps/vendor/electron/LICENSES.chromium.html
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
astilectron-deps/vendor/electron/blink_image_resources_200_percent.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/blink_image_resources_200_percent.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/content_resources_200_percent.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/content_resources_200_percent.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/content_shell.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/content_shell.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/electron
vendored
Executable file
BIN
astilectron-deps/vendor/electron/electron
vendored
Executable file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/icudtl.dat
vendored
Normal file
BIN
astilectron-deps/vendor/electron/icudtl.dat
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/libffmpeg.so
vendored
Normal file
BIN
astilectron-deps/vendor/electron/libffmpeg.so
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/libnode.so
vendored
Executable file
BIN
astilectron-deps/vendor/electron/libnode.so
vendored
Executable file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/am.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/am.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ar.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ar.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/bg.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/bg.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/bn.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/bn.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ca.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ca.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/cs.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/cs.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/da.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/da.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/de.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/de.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/el.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/el.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/en-GB.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/en-GB.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/en-US.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/en-US.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/es-419.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/es-419.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/es.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/es.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/et.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/et.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/fa.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/fa.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/fake-bidi.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/fake-bidi.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/fi.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/fi.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/fil.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/fil.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/fr.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/fr.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/gu.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/gu.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/he.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/he.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/hi.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/hi.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/hr.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/hr.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/hu.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/hu.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/id.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/id.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/it.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/it.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ja.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ja.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/kn.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/kn.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ko.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ko.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/lt.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/lt.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/lv.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/lv.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ml.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ml.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/mr.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/mr.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ms.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ms.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/nb.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/nb.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/nl.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/nl.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/pl.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/pl.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/pt-BR.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/pt-BR.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/pt-PT.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/pt-PT.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ro.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ro.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ru.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ru.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/sk.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/sk.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/sl.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/sl.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/sr.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/sr.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/sv.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/sv.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/sw.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/sw.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/ta.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/ta.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/te.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/te.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/th.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/th.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/tr.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/tr.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/uk.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/uk.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/vi.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/vi.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/zh-CN.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/zh-CN.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/locales/zh-TW.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/locales/zh-TW.pak
vendored
Normal file
Binary file not shown.
14750
astilectron-deps/vendor/electron/natives_blob.bin
vendored
Normal file
14750
astilectron-deps/vendor/electron/natives_blob.bin
vendored
Normal file
File diff suppressed because it is too large
Load Diff
BIN
astilectron-deps/vendor/electron/pdf_viewer_resources.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/pdf_viewer_resources.pak
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/resources/default_app.asar
vendored
Normal file
BIN
astilectron-deps/vendor/electron/resources/default_app.asar
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/resources/electron.asar
vendored
Normal file
BIN
astilectron-deps/vendor/electron/resources/electron.asar
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/snapshot_blob.bin
vendored
Normal file
BIN
astilectron-deps/vendor/electron/snapshot_blob.bin
vendored
Normal file
Binary file not shown.
BIN
astilectron-deps/vendor/electron/ui_resources_200_percent.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/ui_resources_200_percent.pak
vendored
Normal file
Binary file not shown.
1
astilectron-deps/vendor/electron/version
vendored
Normal file
1
astilectron-deps/vendor/electron/version
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
v1.6.5
|
BIN
astilectron-deps/vendor/electron/views_resources_200_percent.pak
vendored
Normal file
BIN
astilectron-deps/vendor/electron/views_resources_200_percent.pak
vendored
Normal file
Binary file not shown.
1
astilectron-deps/vendor/status.json
vendored
Normal file
1
astilectron-deps/vendor/status.json
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
{"astilectron":{"version":"0.6.0"},"electron":{"version":"1.6.5"}}
|
|
@ -6,7 +6,7 @@ AdminPassword = geheim
|
|||
Mode = 1
|
||||
|
||||
; Serverkram
|
||||
; Das Interface inkl. Port, auf dem der Webserver läuft
|
||||
; Das Interface inkl. Port, auf dem der Webserver läuft. Muss komplett mit IP-Adresse vorhanden sein.
|
||||
Interface = 127.0.0.1:8080
|
||||
; Hier wird die Datenbank gespeichert
|
||||
DBFile = ./data.db
|
|
@ -26,6 +26,8 @@ import:
|
|||
- package: google.golang.org/api
|
||||
subpackages:
|
||||
- compute/v1
|
||||
- package: github.com/asticode/go-astilectron
|
||||
version: ~0.5.0
|
||||
testImport:
|
||||
- package: github.com/denisenkom/go-mssqldb
|
||||
- package: github.com/smartystreets/goconvey
|
||||
|
|
4
login.go
4
login.go
|
@ -19,6 +19,10 @@ func login(c echo.Context) error {
|
|||
//Wenn das password stimmt, einloggen
|
||||
if SiteConf.AdminPassword == pass {
|
||||
sess.Set("login", true)
|
||||
direct := c.QueryParam("direct")
|
||||
if direct == "true" {
|
||||
return c.Redirect(http.StatusSeeOther, "/admin")
|
||||
}
|
||||
return c.JSON(http.StatusOK, Message{"success"})
|
||||
} else {
|
||||
return c.JSON(http.StatusOK, Message{"fail"})
|
||||
|
|
106
main.go
106
main.go
|
@ -6,9 +6,14 @@ import (
|
|||
"github.com/labstack/gommon/log"
|
||||
"html/template"
|
||||
|
||||
|
||||
"fmt"
|
||||
"github.com/astaxie/session"
|
||||
_ "github.com/astaxie/session/providers/memory"
|
||||
"github.com/asticode/go-astilectron"
|
||||
"github.com/asticode/go-astilog"
|
||||
"github.com/pkg/errors"
|
||||
"time"
|
||||
)
|
||||
|
||||
//Initialize Session
|
||||
|
@ -85,5 +90,104 @@ func main() {
|
|||
|
||||
//Start the server
|
||||
e.Logger.SetLevel(log.ERROR)
|
||||
e.Start(SiteConf.Interface)
|
||||
go e.Start(SiteConf.Interface)
|
||||
|
||||
//Windows
|
||||
// Create astilectron
|
||||
var a *astilectron.Astilectron
|
||||
var err error
|
||||
if a, err = astilectron.New(astilectron.Options{
|
||||
AppName: "Astilectron",
|
||||
AppIconDefaultPath: "/gopher.png",
|
||||
AppIconDarwinPath: "/gopher.icns",
|
||||
BaseDirectoryPath: "astilectron-deps",
|
||||
}); err != nil {
|
||||
fmt.Println(err)
|
||||
astilog.Fatal(errors.Wrap(err, "creating new astilectron failed"))
|
||||
}
|
||||
defer a.Close()
|
||||
a.HandleSignals()
|
||||
|
||||
// Start
|
||||
if err = a.Start(); err != nil {
|
||||
fmt.Println(err)
|
||||
astilog.Fatal(errors.Wrap(err, "starting failed"))
|
||||
}
|
||||
|
||||
// Create Admin window
|
||||
var wAdmin *astilectron.Window
|
||||
if wAdmin, err = a.NewWindow("http://" + SiteConf.Interface + "/admin", &astilectron.WindowOptions{
|
||||
Center: astilectron.PtrBool(true),
|
||||
Height: astilectron.PtrInt(800),
|
||||
Width: astilectron.PtrInt(1200),
|
||||
}); err != nil {
|
||||
fmt.Println(err)
|
||||
astilog.Fatal(errors.Wrap(err, "new window failed"))
|
||||
}
|
||||
if err = wAdmin.Create(); err != nil {
|
||||
fmt.Println(err)
|
||||
astilog.Fatal(errors.Wrap(err, "creating window failed"))
|
||||
}
|
||||
|
||||
// Create Frontend window
|
||||
var wFrontend *astilectron.Window
|
||||
if wFrontend, err = a.NewWindow("http://" + SiteConf.Interface, &astilectron.WindowOptions{
|
||||
Center: astilectron.PtrBool(true),
|
||||
Height: astilectron.PtrInt(800),
|
||||
Width: astilectron.PtrInt(1200),
|
||||
}); err != nil {
|
||||
fmt.Println(err)
|
||||
astilog.Fatal(errors.Wrap(err, "new window failed"))
|
||||
}
|
||||
if err = wFrontend.Create(); err != nil {
|
||||
fmt.Println(err)
|
||||
astilog.Fatal(errors.Wrap(err, "creating window failed"))
|
||||
}
|
||||
|
||||
// If several displays, move the window to the second display
|
||||
var displays = a.Displays()
|
||||
if len(displays) > 1 {
|
||||
time.Sleep(time.Second)
|
||||
wFrontend.MoveInDisplay(displays[1], 50, 50)
|
||||
wFrontend.Maximize()
|
||||
}
|
||||
|
||||
// Blocking pattern
|
||||
a.Wait()
|
||||
|
||||
|
||||
// Initialize astilectron
|
||||
/*var a, _ = astilectron.New(astilectron.Options{
|
||||
AppName: "Konfi@Castle Kasino Kasse",
|
||||
AppIconDefaultPath: "<your .png icon>",
|
||||
AppIconDarwinPath: "<your .icns icon>",
|
||||
BaseDirectoryPath: "<where you want the provisioner to install the dependencies>",
|
||||
})
|
||||
defer a.Close()
|
||||
|
||||
// Start astilectron
|
||||
a.Start()
|
||||
|
||||
// Create a new window
|
||||
var wAdmin, _ = a.NewWindow("http://" + SiteConf.Interface + "/admin", &astilectron.WindowOptions{
|
||||
Center: astilectron.PtrBool(true),
|
||||
Height: astilectron.PtrInt(800),
|
||||
Width: astilectron.PtrInt(1300),
|
||||
})
|
||||
wAdmin.Create()
|
||||
|
||||
// Create a new window
|
||||
var wFrontend, _ = a.NewWindow("http://" + SiteConf.Interface, &astilectron.WindowOptions{
|
||||
Center: astilectron.PtrBool(true),
|
||||
Height: astilectron.PtrInt(600),
|
||||
Width: astilectron.PtrInt(600),
|
||||
})
|
||||
wFrontend.Create()
|
||||
|
||||
// If several displays, move the window to the second display
|
||||
var displays = a.Displays()
|
||||
if len(displays) > 1 {
|
||||
wFrontend.MoveInDisplay(displays[1], 50, 50)
|
||||
wFrontend.Maximize()
|
||||
}*/
|
||||
}
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>Kasino Admin</title>
|
||||
<link rel="stylesheet" type="text/css" href="/assets/semantic/semantic.min.css">
|
||||
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
<script src="/assets/js/jquery-3.1.1.min.js"></script>
|
||||
<script>if (window.module) module = window.module;</script>
|
||||
<script src="/assets/semantic/semantic.min.js"></script>
|
||||
</head>
|
||||
{{if .Loggedin}}
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>Kasino Admin</title>
|
||||
<link rel="stylesheet" type="text/css" href="/assets/semantic/semantic.min.css">
|
||||
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
<script src="/assets/js/jquery-3.1.1.min.js"></script>
|
||||
<script>if (window.module) module = window.module;</script>
|
||||
<script src="/assets/semantic/semantic.min.js"></script>
|
||||
</head>
|
||||
{{if .Loggedin}}
|
||||
|
|
|
@ -31,7 +31,9 @@
|
|||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
<script src="/assets/js/jquery-3.1.1.min.js"></script>
|
||||
<script>if (window.module) module = window.module;</script>
|
||||
<script src="/assets/js/load.js"></script>
|
||||
</body>
|
||||
</html>
|
||||
|
|
|
@ -5,7 +5,10 @@
|
|||
<meta charset="UTF-8">
|
||||
<title>Kasino Admin</title>
|
||||
<link rel="stylesheet" type="text/css" href="/assets/semantic/semantic.min.css">
|
||||
|
||||
<script>if (typeof module === 'object') {window.module = module; module = undefined;}</script>
|
||||
<script src="/assets/js/jquery-3.1.1.min.js"></script>
|
||||
<script>if (window.module) module = window.module;</script>
|
||||
<script src="/assets/semantic/semantic.min.js"></script>
|
||||
</head>
|
||||
<body style="background: url(/assets/bg.jpg) no-repeat center fixed">
|
||||
|
@ -14,7 +17,7 @@
|
|||
<h2 class="ui header">
|
||||
Kasino Admin
|
||||
</h2>
|
||||
<form class="ui large form" id="loginform" method="post">
|
||||
<form class="ui large form" id="loginform" method="post" onsubmit="login();return false;" action="/login?direct=true">
|
||||
<div class="ui segment">
|
||||
<div class="field">
|
||||
<div class="ui left icon input">
|
||||
|
|
8
vendor/github.com/asticode/go-astilectron/.gitignore
generated
vendored
Normal file
8
vendor/github.com/asticode/go-astilectron/.gitignore
generated
vendored
Normal file
|
@ -0,0 +1,8 @@
|
|||
.DS_Store
|
||||
Thumbs.db
|
||||
.idea/
|
||||
cover.*
|
||||
examples/5.single_binary_distribution/vendor.go
|
||||
examples/test
|
||||
examples/vendor
|
||||
testdata/tmp/*
|
9
vendor/github.com/asticode/go-astilectron/.travis.yml
generated
vendored
Normal file
9
vendor/github.com/asticode/go-astilectron/.travis.yml
generated
vendored
Normal file
|
@ -0,0 +1,9 @@
|
|||
language: go
|
||||
go:
|
||||
- 1.8
|
||||
- tip
|
||||
matrix:
|
||||
allow_failures:
|
||||
- go: tip
|
||||
script:
|
||||
go test -v
|
21
vendor/github.com/asticode/go-astilectron/LICENSE
generated
vendored
Normal file
21
vendor/github.com/asticode/go-astilectron/LICENSE
generated
vendored
Normal file
|
@ -0,0 +1,21 @@
|
|||
The MIT License (MIT)
|
||||
|
||||
Copyright (c) 2017 Quentin RENARD
|
||||
|
||||
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.
|
646
vendor/github.com/asticode/go-astilectron/README.md
generated
vendored
Normal file
646
vendor/github.com/asticode/go-astilectron/README.md
generated
vendored
Normal file
|
@ -0,0 +1,646 @@
|
|||
[![GoReportCard](http://goreportcard.com/badge/github.com/asticode/go-astilectron)](http://goreportcard.com/report/github.com/asticode/go-astilectron)
|
||||
[![GoDoc](https://godoc.org/github.com/asticode/go-astilectron?status.svg)](https://godoc.org/github.com/asticode/go-astilectron)
|
||||
[![GoCoverage](https://cover.run/go/github.com/asticode/go-astilectron.svg)](https://cover.run/go/github.com/asticode/go-astilectron)
|
||||
[![Travis](https://travis-ci.org/asticode/go-astilectron.svg?branch=master)](https://travis-ci.org/asticode/go-astilectron#)
|
||||
|
||||
Thanks to `go-astilectron` build cross platform GUI apps with GO and HTML/JS/CSS. It is the official GO bindings of [astilectron](https://github.com/asticode/astilectron) and is powered by [Electron](https://github.com/electron/electron).
|
||||
|
||||
# Real-life examples
|
||||
|
||||
Here's a list of awesome projects using `go-astilectron` (if you're using `go-astilectron` and want your project to be listed here please submit a PR):
|
||||
|
||||
- [go-astivid](https://github.com/asticode/go-astivid) Video tools written in GO
|
||||
- [GroupMatcher](https://github.com/veecue/GroupMatcher) Program to allocate persons to groups while trying to fulfill all the given wishes as good as possible
|
||||
|
||||
# Quick start
|
||||
|
||||
WARNING: the code below doesn't handle errors for readibility purposes. However you SHOULD!
|
||||
|
||||
### Import `go-astilectron`
|
||||
|
||||
To import `go-astilectron` run:
|
||||
|
||||
$ go get -u github.com/asticode/go-astilectron
|
||||
|
||||
### Start `go-astilectron`
|
||||
|
||||
```go
|
||||
// Initialize astilectron
|
||||
var a, _ = astilectron.New(astilectron.Options{
|
||||
AppName: "<your app name>",
|
||||
AppIconDefaultPath: "<your .png icon>",
|
||||
AppIconDarwinPath: "<your .icns icon>",
|
||||
BaseDirectoryPath: "<where you want the provisioner to install the dependencies>",
|
||||
})
|
||||
defer a.Close()
|
||||
|
||||
// Start astilectron
|
||||
a.Start()
|
||||
```
|
||||
|
||||
For everything to work properly we need to fetch 2 dependencies : [astilectron](https://github.com/asticode/astilectron) and [Electron](https://github.com/electron/electron). `.Start()` takes care of it by downloading the sources and setting them up properly.
|
||||
|
||||
In case you want to embed the sources in the binary to keep a unique binary you can use the **NewDisembedderProvisioner** function to get the proper **Provisioner** and attach it to `go-astilectron` with `.SetProvisioner(p Provisioner)`. Check out the [example](https://github.com/asticode/go-astilectron/tree/master/examples/5.single_binary_distribution/main.go) to see how to use it with [go-bindata](https://github.com/jteeuwen/go-bindata).
|
||||
|
||||
Beware when trying to add your own app icon as you'll need 2 icons : one compatible with MacOSX (.icns) and one compatible with the rest (.png for instance).
|
||||
|
||||
If no BaseDirectoryPath is provided, it defaults to the executable's directory path.
|
||||
|
||||
The majority of methods are synchrone which means that when executing them `go-astilectron` will block until it receives a specific Electron event or until the overall context is cancelled. This is the case of `.Start()` which will block until it receives the `app.event.ready` `astilectron` event or until the overall context is cancelled.
|
||||
|
||||
### Create a window
|
||||
|
||||
```go
|
||||
// Create a new window
|
||||
var w, _ = a.NewWindow("http://127.0.0.1:4000", &astilectron.WindowOptions{
|
||||
Center: astilectron.PtrBool(true),
|
||||
Height: astilectron.PtrInt(600),
|
||||
Width: astilectron.PtrInt(600),
|
||||
})
|
||||
w.Create()
|
||||
```
|
||||
|
||||
When creating a window you need to indicate a URL as well as options such as position, size, etc.
|
||||
|
||||
This is pretty straightforward except the `astilectron.Ptr*` methods so let me explain: GO doesn't do optional fields when json encoding unless you use pointers whereas Electron does handle optional fields. Therefore I added helper methods to convert int, bool and string into pointers and used pointers in structs sent to Electron.
|
||||
|
||||
### Add listeners
|
||||
|
||||
```go
|
||||
// Add a listener on Astilectron
|
||||
a.On(astilectron.EventNameAppCrash, func(e astilectron.Event) (deleteListener bool) {
|
||||
astilog.Error("App has crashed")
|
||||
return
|
||||
})
|
||||
|
||||
// Add a listener on the window
|
||||
w.On(astilectron.EventNameWindowEventResize, func(e astilectron.Event) (deleteListener bool) {
|
||||
astilog.Info("Window resized")
|
||||
return
|
||||
})
|
||||
```
|
||||
|
||||
Nothing much to say here either except that you can add listeners to Astilectron as well.
|
||||
|
||||
### Play with the window
|
||||
|
||||
```go
|
||||
// Play with the window
|
||||
w.Resize(200, 200)
|
||||
time.Sleep(time.Second)
|
||||
w.Maximize()
|
||||
```
|
||||
|
||||
Check out the [Window doc](https://godoc.org/github.com/asticode/go-astilectron#Window) for a list of all exported methods
|
||||
|
||||
### Send messages between GO and your webserver
|
||||
|
||||
In your webserver add the following javascript to any of the pages you want to interact with:
|
||||
|
||||
```html
|
||||
<script>
|
||||
// This will wait for the astilectron namespace to be ready
|
||||
document.addEventListener('astilectron-ready', function() {
|
||||
|
||||
// This will listen to messages sent by GO
|
||||
astilectron.listen(function(message) {
|
||||
|
||||
// This will send a message back to GO
|
||||
astilectron.send("I'm good bro")
|
||||
});
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
In your GO app add the following:
|
||||
|
||||
```go
|
||||
// Listen to messages sent by webserver
|
||||
w.On(astilectron.EventNameWindowEventMessage, func(e astilectron.Event) (deleteListener bool) {
|
||||
var m string
|
||||
e.Message.Unmarshal(&m)
|
||||
astilog.Infof("Received message %s", m)
|
||||
return
|
||||
})
|
||||
|
||||
// Send message to webserver
|
||||
w.Send("What's up?")
|
||||
```
|
||||
|
||||
And that's it!
|
||||
|
||||
NOTE: needless to say that the message can be something other than a string. A custom struct for instance!
|
||||
|
||||
### Handle several screens/displays
|
||||
|
||||
```go
|
||||
// If several displays, move the window to the second display
|
||||
var displays = a.Displays()
|
||||
if len(displays) > 1 {
|
||||
time.Sleep(time.Second)
|
||||
w.MoveInDisplay(displays[1], 50, 50)
|
||||
}
|
||||
```
|
||||
|
||||
### Menus
|
||||
|
||||
```go
|
||||
// Init a new app menu
|
||||
// You can do the same thing with a window
|
||||
var m = a.NewMenu([]*astilectron.MenuItemOptions{
|
||||
{
|
||||
Label: astilectron.PtrStr("Separator"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Normal 1")},
|
||||
{
|
||||
Label: astilectron.PtrStr("Normal 2"),
|
||||
OnClick: func(e astilectron.Event) (deleteListener bool) {
|
||||
astilog.Info("Normal 2 item has been clicked")
|
||||
return
|
||||
},
|
||||
},
|
||||
{Type: astilectron.MenuItemTypeSeparator},
|
||||
{Label: astilectron.PtrStr("Normal 3")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Checkbox"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Checked: astilectron.PtrBool(true), Label: astilectron.PtrStr("Checkbox 1"), Type: astilectron.MenuItemTypeCheckbox},
|
||||
{Label: astilectron.PtrStr("Checkbox 2"), Type: astilectron.MenuItemTypeCheckbox},
|
||||
{Label: astilectron.PtrStr("Checkbox 3"), Type: astilectron.MenuItemTypeCheckbox},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Radio"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Checked: astilectron.PtrBool(true), Label: astilectron.PtrStr("Radio 1"), Type: astilectron.MenuItemTypeRadio},
|
||||
{Label: astilectron.PtrStr("Radio 2"), Type: astilectron.MenuItemTypeRadio},
|
||||
{Label: astilectron.PtrStr("Radio 3"), Type: astilectron.MenuItemTypeRadio},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Roles"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Minimize"), Role: astilectron.MenuItemRoleMinimize},
|
||||
{Label: astilectron.PtrStr("Close"), Role: astilectron.MenuItemRoleClose},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Retrieve a menu item
|
||||
// This will retrieve the "Checkbox 1" item
|
||||
mi, _ := m.Item(1, 0)
|
||||
|
||||
// Add listener manually
|
||||
// An OnClick listener has already been added in the options directly for another menu item
|
||||
mi.On(astilectron.EventNameMenuItemEventClicked, func(e astilectron.Event) bool {
|
||||
astilog.Infof("Menu item has been clicked. 'Checked' status is now %t", *e.MenuItemOptions.Checked)
|
||||
return false
|
||||
})
|
||||
|
||||
// Create the menu
|
||||
m.Create()
|
||||
|
||||
// Manipulate a menu item
|
||||
mi.SetChecked(true)
|
||||
|
||||
// Init a new menu item
|
||||
var ni = m.NewItem(&astilectron.MenuItemOptions{
|
||||
Label: astilectron.PtrStr("Inserted"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Inserted 1")},
|
||||
{Label: astilectron.PtrStr("Inserted 2")},
|
||||
},
|
||||
})
|
||||
|
||||
// Insert the menu item at position "1"
|
||||
m.Insert(1, ni)
|
||||
|
||||
// Fetch a sub menu
|
||||
s, _ := m.SubMenu(0)
|
||||
|
||||
// Init a new menu item
|
||||
ni = s.NewItem(&astilectron.MenuItemOptions{
|
||||
Label: astilectron.PtrStr("Appended"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Appended 1")},
|
||||
{Label: astilectron.PtrStr("Appended 2")},
|
||||
},
|
||||
})
|
||||
|
||||
// Append menu item dynamically
|
||||
s.Append(ni)
|
||||
|
||||
// Pop up sub menu as a context menu
|
||||
s.Popup(&astilectron.MenuPopupOptions{PositionOptions: astilectron.PositionOptions{X: astilectron.PtrInt(50), Y: astilectron.PtrInt(50)}})
|
||||
|
||||
// Close popup
|
||||
s.ClosePopup()
|
||||
|
||||
// Destroy the menu
|
||||
m.Destroy()
|
||||
```
|
||||
|
||||
A few things to know:
|
||||
|
||||
* when assigning a role to a menu item, `go-astilectron` won't be able to capture its click event
|
||||
* on MacOS there's no such thing as a window menu, only app menus therefore my advice is to stick to one global app menu instead of creating separate window menus
|
||||
|
||||
### Tray
|
||||
|
||||
```go
|
||||
// New tray
|
||||
var t = a.NewTray(&astilectron.TrayOptions{
|
||||
Image: astilectron.PtrStr("/path/to/image.png"),
|
||||
Tooltip: astilectron.PtrStr("Tray's tooltip"),
|
||||
})
|
||||
|
||||
// New tray menu
|
||||
var m = t.NewMenu([]*astilectron.MenuItemOptions{
|
||||
{
|
||||
Label: astilectron.PtrStr("Root 1"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Item 1")},
|
||||
{Label: astilectron.PtrStr("Item 2")},
|
||||
{Type: astilectron.MenuItemTypeSeparator},
|
||||
{Label: astilectron.PtrStr("Item 3")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Root 2"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Item 1")},
|
||||
{Label: astilectron.PtrStr("Item 2")},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Create the menu
|
||||
m.Create()
|
||||
|
||||
// Create tray
|
||||
t.Create()
|
||||
```
|
||||
|
||||
### Dialogs
|
||||
|
||||
In your webserver add one of the following javascript to achieve any kind of dialog.
|
||||
|
||||
#### Error box
|
||||
|
||||
```html
|
||||
<script>
|
||||
// This will wait for the astilectron namespace to be ready
|
||||
document.addEventListener('astilectron-ready', function() {
|
||||
// This will open the dialog
|
||||
astilectron.showErrorBox("My Title", "My content")
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Message box
|
||||
|
||||
```html
|
||||
<script>
|
||||
// This will wait for the astilectron namespace to be ready
|
||||
document.addEventListener('astilectron-ready', function() {
|
||||
// This will open the dialog
|
||||
astilectron.showMessageBox({message: "My message", title: "My Title"})
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Open dialog
|
||||
|
||||
```html
|
||||
<script>
|
||||
// This will wait for the astilectron namespace to be ready
|
||||
document.addEventListener('astilectron-ready', function() {
|
||||
// This will open the dialog
|
||||
astilectron.showOpenDialog({properties: ['openFile', 'multiSelections'], title: "My Title"}, function(paths) {
|
||||
console.log("chosen paths are ", paths)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
#### Save dialog
|
||||
|
||||
```html
|
||||
<script>
|
||||
// This will wait for the astilectron namespace to be ready
|
||||
document.addEventListener('astilectron-ready', function() {
|
||||
// This will open the dialog
|
||||
astilectron.showSaveDialog({title: "My title"}, function(filename) {
|
||||
console.log("chosen filename is ", filename)
|
||||
})
|
||||
})
|
||||
</script>
|
||||
```
|
||||
|
||||
### Final code
|
||||
|
||||
```go
|
||||
// Set up the logger
|
||||
var l <your logger type>
|
||||
astilog.SetLogger(l)
|
||||
|
||||
// Start an http server
|
||||
http.HandleFunc("/", func(w http.ResponseWriter, r *http.Request) {
|
||||
w.Write([]byte(`<!DOCTYPE html>
|
||||
<html lang="en">
|
||||
<head>
|
||||
<meta charset="UTF-8">
|
||||
<title>Hello world</title>
|
||||
</head>
|
||||
<body>
|
||||
<span id="message">Hello world</span>
|
||||
<script>
|
||||
// This will wait for the astilectron namespace to be ready
|
||||
document.addEventListener('astilectron-ready', function() {
|
||||
// This will listen to messages sent by GO
|
||||
astilectron.listen(function(message) {
|
||||
document.getElementById('message').innerHTML = message
|
||||
// This will send a message back to GO
|
||||
astilectron.send("I'm good bro")
|
||||
});
|
||||
})
|
||||
</script>
|
||||
</body>
|
||||
</html>`))
|
||||
})
|
||||
go http.ListenAndServe("127.0.0.1:4000", nil)
|
||||
|
||||
// Initialize astilectron
|
||||
var a, _ = astilectron.New(astilectron.Options{
|
||||
AppName: "<your app name>",
|
||||
AppIconDefaultPath: "<your .png icon>",
|
||||
AppIconDarwinPath: "<your .icns icon>",
|
||||
BaseDirectoryPath: "<where you want the provisioner to install the dependencies>",
|
||||
})
|
||||
defer a.Close()
|
||||
|
||||
// Handle quit
|
||||
a.HandleSignals()
|
||||
a.On(astilectron.EventNameAppCrash, func(e astilectron.Event) (deleteListener bool) {
|
||||
astilog.Error("App has crashed")
|
||||
return
|
||||
})
|
||||
|
||||
// Start astilectron: this will download and set up the dependencies, and start the Electron app
|
||||
a.Start()
|
||||
|
||||
// Init a new app menu
|
||||
// You can do the same thing with a window
|
||||
var m = a.NewMenu([]*astilectron.MenuItemOptions{
|
||||
{
|
||||
Label: astilectron.PtrStr("Separator"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Normal 1")},
|
||||
{
|
||||
Label: astilectron.PtrStr("Normal 2"),
|
||||
OnClick: func(e astilectron.Event) (deleteListener bool) {
|
||||
astilog.Info("Normal 2 item has been clicked")
|
||||
return
|
||||
},
|
||||
},
|
||||
{Type: astilectron.MenuItemTypeSeparator},
|
||||
{Label: astilectron.PtrStr("Normal 3")},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Checkbox"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Checked: astilectron.PtrBool(true), Label: astilectron.PtrStr("Checkbox 1"), Type: astilectron.MenuItemTypeCheckbox},
|
||||
{Label: astilectron.PtrStr("Checkbox 2"), Type: astilectron.MenuItemTypeCheckbox},
|
||||
{Label: astilectron.PtrStr("Checkbox 3"), Type: astilectron.MenuItemTypeCheckbox},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Radio"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Checked: astilectron.PtrBool(true), Label: astilectron.PtrStr("Radio 1"), Type: astilectron.MenuItemTypeRadio},
|
||||
{Label: astilectron.PtrStr("Radio 2"), Type: astilectron.MenuItemTypeRadio},
|
||||
{Label: astilectron.PtrStr("Radio 3"), Type: astilectron.MenuItemTypeRadio},
|
||||
},
|
||||
},
|
||||
{
|
||||
Label: astilectron.PtrStr("Roles"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Minimize"), Role: astilectron.MenuItemRoleMinimize},
|
||||
{Label: astilectron.PtrStr("Close"), Role: astilectron.MenuItemRoleClose},
|
||||
},
|
||||
},
|
||||
})
|
||||
|
||||
// Retrieve a menu item
|
||||
// This will retrieve the "Checkbox 1" item
|
||||
mi, _ := m.Item(1, 0)
|
||||
|
||||
// Add listener manually
|
||||
// An OnClick listener has already been added in the options directly for another menu item
|
||||
mi.On(astilectron.EventNameMenuItemEventClicked, func(e astilectron.Event) bool {
|
||||
astilog.Infof("Menu item has been clicked. 'Checked' status is now %t", *e.MenuItemOptions.Checked)
|
||||
return false
|
||||
})
|
||||
|
||||
// Create the menu
|
||||
m.Create()
|
||||
|
||||
// Create a new window with a listener on resize
|
||||
var w, _ = a.NewWindow("http://127.0.0.1:4000", &astilectron.WindowOptions{
|
||||
Center: astilectron.PtrBool(true),
|
||||
Height: astilectron.PtrInt(600),
|
||||
Icon: astilectron.PtrStr(<your icon path>),
|
||||
Width: astilectron.PtrInt(600),
|
||||
})
|
||||
w.On(astilectron.EventNameWindowEventResize, func(e astilectron.Event) (deleteListener bool) {
|
||||
astilog.Info("Window resized")
|
||||
return
|
||||
})
|
||||
w.On(astilectron.EventNameWindowEventMessage, func(e astilectron.Event) (deleteListener bool) {
|
||||
var m string
|
||||
e.Message.Unmarshal(&m)
|
||||
astilog.Infof("Received message %s", m)
|
||||
return
|
||||
})
|
||||
w.Create()
|
||||
|
||||
// Play with the window
|
||||
w.Resize(200, 200)
|
||||
time.Sleep(time.Second)
|
||||
w.Maximize()
|
||||
|
||||
// If several displays, move the window to the second display
|
||||
var displays = a.Displays()
|
||||
if len(displays) > 1 {
|
||||
time.Sleep(time.Second)
|
||||
w.MoveInDisplay(displays[1], 50, 50)
|
||||
}
|
||||
|
||||
// Send a message to the server
|
||||
time.Sleep(time.Second)
|
||||
w.Send("What's up?")
|
||||
|
||||
// Manipulate a menu item
|
||||
time.Sleep(time.Second)
|
||||
mi.SetChecked(true)
|
||||
|
||||
// Init a new menu item
|
||||
var ni = m.NewItem(&astilectron.MenuItemOptions{
|
||||
Label: astilectron.PtrStr("Inserted"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Inserted 1")},
|
||||
{Label: astilectron.PtrStr("Inserted 2")},
|
||||
},
|
||||
})
|
||||
|
||||
// Insert the menu item at position "1"
|
||||
time.Sleep(time.Second)
|
||||
m.Insert(1, ni)
|
||||
|
||||
// Fetch a sub menu
|
||||
s, _ := m.SubMenu(0)
|
||||
|
||||
// Init a new menu item
|
||||
ni = s.NewItem(&astilectron.MenuItemOptions{
|
||||
Label: astilectron.PtrStr("Appended"),
|
||||
SubMenu: []*astilectron.MenuItemOptions{
|
||||
{Label: astilectron.PtrStr("Appended 1")},
|
||||
{Label: astilectron.PtrStr("Appended 2")},
|
||||
},
|
||||
})
|
||||
|
||||
// Append menu item dynamically
|
||||
time.Sleep(time.Second)
|
||||
s.Append(ni)
|
||||
|
||||
// Pop up sub menu as a context menu
|
||||
time.Sleep(time.Second)
|
||||
s.Popup(&astilectron.MenuPopupOptions{PositionOptions: astilectron.PositionOptions{X: astilectron.PtrInt(50), Y: astilectron.PtrInt(50)}})
|
||||
|
||||
// Close popup
|
||||
time.Sleep(time.Second)
|
||||
s.ClosePopup()
|
||||
|
||||
// Destroy the menu
|
||||
time.Sleep(time.Second)
|
||||
m.Destroy()
|
||||
|
||||
// Blocking pattern
|
||||
a.Wait()
|
||||
```
|
||||
|
||||
# Bootstrap
|
||||
|
||||
For convenience purposes I've added a **bootstrap** to help first timers and avoid code duplications.
|
||||
|
||||
NOTE: you DON'T have to use the bootstrap, it's entirely up to you whether to use it or not.
|
||||
|
||||
The bootstrap allows you to quickly create a one-window application.
|
||||
|
||||
## Using static files and remote messaging (the best way)
|
||||
|
||||
In order to use the **bootstrap** with static files and remote messaging you must:
|
||||
|
||||
- follow the following project organization:
|
||||
|
||||
|--+ resources
|
||||
|
|
||||
|--+ app (contains your static files such as .html, .css, .js, .png, etc.)
|
||||
|--+ main.go
|
||||
|
||||
- use the `MessageHandler` **bootstrap** option in order to handle remote messaging
|
||||
- use `remote messaging` in your static files
|
||||
|
||||
## Using a web server
|
||||
|
||||
In order to use the **bootstrap** with a web server you must:
|
||||
|
||||
- follow the following project organization:
|
||||
|
||||
|--+ resources
|
||||
|
|
||||
|--+ static (contains your static files such as .css, .js, .png, etc.)
|
||||
|
|
||||
|--+ templates (contains your templates .html files)
|
||||
|--+ main.go
|
||||
- use the `AdaptRouter` and `TemplateData` **bootstrap** options in order to handle the server routes
|
||||
|
||||
## Common
|
||||
|
||||
- if you're using the `RestoreAssets` **bootstrap** option, add the following comment on top of your `main()` method:
|
||||
|
||||
//go:generate go-bindata -pkg $GOPACKAGE -o resources.go resources/...
|
||||
|
||||
and run the following command before building your binary:
|
||||
|
||||
$ go generate main.go
|
||||
|
||||
- use the `bootstrap.Run()` method
|
||||
|
||||
Check out the [example](https://github.com/asticode/go-astilectron/tree/master/examples/9.bootstrap) for a detailed working example (see the **Examples** section below for the specific commands to run).
|
||||
|
||||
# I want to see it in actions!
|
||||
|
||||
To make things clearer I've tried to split features in different [examples](https://github.com/asticode/go-astilectron/tree/master/examples).
|
||||
|
||||
To run any of the examples, run the following commands:
|
||||
|
||||
$ go run examples/<name of the example>/main.go -v
|
||||
|
||||
Here's a list of the examples:
|
||||
|
||||
- [1.basic_window](https://github.com/asticode/go-astilectron/tree/master/examples/1.basic_window/main.go) creates a basic window that displays a static .html file
|
||||
- [2.basic_window_events](https://github.com/asticode/go-astilectron/tree/master/examples/2.basic_window_events/main.go) plays with basic window methods and shows you how to set up your own listeners
|
||||
- [3.webserver_app](https://github.com/asticode/go-astilectron/tree/master/examples/3.webserver_app/main.go) sets up a basic webserver app
|
||||
- [4.remote_messaging](https://github.com/asticode/go-astilectron/tree/master/examples/4.remote_messaging/main.go) sends a message to the webserver and listens for any response
|
||||
- [5.single_binary_distribution](https://github.com/asticode/go-astilectron/tree/master/examples/5.single_binary_distribution/main.go) shows how to use `go-astilectron` in a unique binary. For this example you have to run one of the previous examples (so that the .zip files exist) and run the following commands:
|
||||
|
||||
```
|
||||
$ go generate examples/5.single_binary_distribution/main.go
|
||||
$ go run examples/5.single_binary_distribution/main.go examples/5.single_binary_distribution/vendor.go -v
|
||||
```
|
||||
|
||||
- [6.screens_and_displays](https://github.com/asticode/go-astilectron/tree/master/examples/6.screens_and_displays/main.go) plays around with screens and displays
|
||||
- [7.menus](https://github.com/asticode/go-astilectron/tree/master/examples/7.menus/main.go) creates and manipulates menus
|
||||
- [8.bootstrap](https://github.com/asticode/go-astilectron/tree/master/examples/8.bootstrap) shows how to use the **bootstrap**. For this example you have to run the following commands:
|
||||
|
||||
```
|
||||
$ go generate examples/8.bootstrap/main.go
|
||||
$ go run examples/8.bootstrap/main.go examples/8.bootstrap/resources.go -v
|
||||
```
|
||||
|
||||
- [9.tray](https://github.com/asticode/go-astilectron/tree/master/examples/9.tray/main.go) creates a tray
|
||||
|
||||
# Features and roadmap
|
||||
|
||||
- [x] custom branding (custom app name, app icon, etc.)
|
||||
- [x] window basic methods (create, show, close, resize, minimize, maximize, ...)
|
||||
- [x] window basic events (close, blur, focus, unresponsive, crashed, ...)
|
||||
- [x] remote messaging (messages between GO and the JS in the webserver)
|
||||
- [x] single binary distribution
|
||||
- [x] multi screens/displays
|
||||
- [x] menu methods and events (create, insert, append, popup, clicked, ...)
|
||||
- [x] bootstrap
|
||||
- [x] dialogs (open or save file, alerts, ...)
|
||||
- [x] tray
|
||||
- [ ] loader
|
||||
- [ ] bundle helper
|
||||
- [ ] accelerators (shortcuts)
|
||||
- [ ] file methods (drag & drop, ...)
|
||||
- [ ] clipboard methods
|
||||
- [ ] power monitor events (suspend, resume, ...)
|
||||
- [ ] notifications (macosx)
|
||||
- [ ] desktop capturer (audio and video)
|
||||
- [ ] session methods
|
||||
- [ ] session events
|
||||
- [ ] window advanced options (add missing ones)
|
||||
- [ ] window advanced methods (add missing ones)
|
||||
- [ ] window advanced events (add missing ones)
|
||||
- [ ] child windows
|
||||
|
||||
# Cheers to
|
||||
|
||||
[go-thrust](https://github.com/miketheprogrammer/go-thrust) which is awesome but unfortunately not maintained anymore. It inspired this project.
|
389
vendor/github.com/asticode/go-astilectron/astilectron.go
generated
vendored
Normal file
389
vendor/github.com/asticode/go-astilectron/astilectron.go
generated
vendored
Normal file
|
@ -0,0 +1,389 @@
|
|||
package astilectron
|
||||
|
||||
import (
|
||||
"flag"
|
||||
"fmt"
|
||||
"net"
|
||||
"os"
|
||||
"os/exec"
|
||||
"os/signal"
|
||||
"runtime"
|
||||
"strings"
|
||||
"syscall"
|
||||
"time"
|
||||
|
||||
"github.com/asticode/go-astilog"
|
||||
"github.com/asticode/go-astitools/context"
|
||||
"github.com/asticode/go-astitools/exec"
|
||||
"github.com/asticode/go-astitools/slice"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// Versions
|
||||
const (
|
||||
VersionAstilectron = "0.6.0"
|
||||
VersionElectron = "1.6.5"
|
||||
)
|
||||
|
||||
// Misc vars
|
||||
var (
|
||||
astilectronDirectoryPath = flag.String("astilectron-directory-path", "", "the astilectron directory path")
|
||||
validOSes = []string{"darwin", "linux", "windows"}
|
||||
)
|
||||
|
||||
// App event names
|
||||
const (
|
||||
EventNameAppClose = "app.close"
|
||||
EventNameAppCmdStop = "app.cmd.stop"
|
||||
EventNameAppCrash = "app.crash"
|
||||
EventNameAppErrorAccept = "app.error.accept"
|
||||
EventNameAppEventReady = "app.event.ready"
|
||||
EventNameAppNoAccept = "app.no.accept"
|
||||
EventNameAppTooManyAccept = "app.too.many.accept"
|
||||
)
|
||||
|
||||
// Astilectron represents an object capable of interacting with Astilectron
|
||||
// TODO Fix race conditions
|
||||
type Astilectron struct {
|
||||
canceller *asticontext.Canceller
|
||||
channelQuit chan bool
|
||||
dispatcher *Dispatcher
|
||||
displayPool *displayPool
|
||||
identifier *identifier
|
||||
listener net.Listener
|
||||
options Options
|
||||
paths *Paths
|
||||
provisioner Provisioner
|
||||
reader *reader
|
||||
stderrWriter *astiexec.StdWriter
|
||||
stdoutWriter *astiexec.StdWriter
|
||||
writer *writer
|
||||
}
|
||||
|
||||
// Options represents Astilectron options
|
||||
type Options struct {
|
||||
AppName string
|
||||
AppIconDarwinPath string // Darwin systems requires a specific .icns file
|
||||
AppIconDefaultPath string
|
||||
BaseDirectoryPath string
|
||||
}
|
||||
|
||||
// New creates a new Astilectron instance
|
||||
func New(o Options) (a *Astilectron, err error) {
|
||||
// Validate the OS
|
||||
if err = validateOS(runtime.GOOS); err != nil {
|
||||
err = errors.Wrap(err, "validating OS failed")
|
||||
return
|
||||
}
|
||||
a = &Astilectron{
|
||||
canceller: asticontext.NewCanceller(),
|
||||
channelQuit: make(chan bool),
|
||||
dispatcher: newDispatcher(),
|
||||
displayPool: newDisplayPool(),
|
||||
identifier: newIdentifier(),
|
||||
options: o,
|
||||
provisioner: DefaultProvisioner,
|
||||
}
|
||||
|
||||
// Set paths
|
||||
if a.paths, err = newPaths(runtime.GOOS, runtime.GOARCH, o); err != nil {
|
||||
err = errors.Wrap(err, "creating new paths failed")
|
||||
return
|
||||
}
|
||||
|
||||
// Add default listeners
|
||||
a.On(EventNameAppCmdStop, func(e Event) (deleteListener bool) {
|
||||
a.Stop()
|
||||
return
|
||||
})
|
||||
a.On(EventNameDisplayEventAdded, func(e Event) (deleteListener bool) {
|
||||
a.displayPool.update(e.Displays)
|
||||
return
|
||||
})
|
||||
a.On(EventNameDisplayEventMetricsChanged, func(e Event) (deleteListener bool) {
|
||||
a.displayPool.update(e.Displays)
|
||||
return
|
||||
})
|
||||
a.On(EventNameDisplayEventRemoved, func(e Event) (deleteListener bool) {
|
||||
a.displayPool.update(e.Displays)
|
||||
return
|
||||
})
|
||||
return
|
||||
}
|
||||
|
||||
// validateOS validates the OS
|
||||
func validateOS(os string) error {
|
||||
if !astislice.InStringSlice(os, validOSes) {
|
||||
return fmt.Errorf("OS %s is not supported", os)
|
||||
}
|
||||
return nil
|
||||
}
|
||||
|
||||
// ValidOSes returns a slice containing the names of all currently supported operating systems
|
||||
func ValidOSes() []string {
|
||||
return append(make([]string, 0, len(validOSes)), validOSes...)
|
||||
}
|
||||
|
||||
// SetProvisioner sets the provisioner
|
||||
func (a *Astilectron) SetProvisioner(p Provisioner) *Astilectron {
|
||||
a.provisioner = p
|
||||
return a
|
||||
}
|
||||
|
||||
// On implements the Listenable interface
|
||||
func (a *Astilectron) On(eventName string, l Listener) {
|
||||
a.dispatcher.addListener(mainTargetID, eventName, l)
|
||||
}
|
||||
|
||||
// Start starts Astilectron
|
||||
func (a *Astilectron) Start() (err error) {
|
||||
// Log
|
||||
astilog.Debug("Starting...")
|
||||
|
||||
// Start the dispatcher
|
||||
go a.dispatcher.start()
|
||||
|
||||
// Provision
|
||||
if err = a.provision(); err != nil {
|
||||
return errors.Wrap(err, "provisioning failed")
|
||||
}
|
||||
|
||||
// Unfortunately communicating with Electron through stdin/stdout doesn't work on Windows so all communications
|
||||
// will be done through TCP
|
||||
if err = a.listenTCP(); err != nil {
|
||||
return errors.Wrap(err, "listening failed")
|
||||
}
|
||||
|
||||
// Execute
|
||||
if err = a.execute(); err != nil {
|
||||
err = errors.Wrap(err, "executing failed")
|
||||
return
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// provision provisions Astilectron
|
||||
func (a *Astilectron) provision() error {
|
||||
astilog.Debug("Provisioning...")
|
||||
var ctx, _ = a.canceller.NewContext()
|
||||
return a.provisioner.Provision(ctx, *a.dispatcher, a.options.AppName, runtime.GOOS, *a.paths)
|
||||
}
|
||||
|
||||
// listenTCP listens to the first TCP connection coming its way (this should be Astilectron)
|
||||
func (a *Astilectron) listenTCP() (err error) {
|
||||
// Log
|
||||
astilog.Debug("Listening...")
|
||||
|
||||
// Listen
|
||||
if a.listener, err = net.Listen("tcp", "127.0.0.1:"); err != nil {
|
||||
return errors.Wrap(err, "tcp net.Listen failed")
|
||||
}
|
||||
|
||||
// Check a connection has been accepted quickly enough
|
||||
var chanAccepted = make(chan bool)
|
||||
go a.watchNoAccept(30*time.Second, chanAccepted)
|
||||
|
||||
// Accept connections
|
||||
go a.acceptTCP(chanAccepted)
|
||||
return
|
||||
}
|
||||
|
||||
// watchNoAccept checks whether a TCP connection is accepted quickly enough
|
||||
func (a *Astilectron) watchNoAccept(timeout time.Duration, chanAccepted chan bool) {
|
||||
var t = time.NewTimer(timeout)
|
||||
defer t.Stop()
|
||||
for {
|
||||
select {
|
||||
case <-chanAccepted:
|
||||
return
|
||||
case <-t.C:
|
||||
astilog.Errorf("No TCP connection has been accepted in the past %s", timeout)
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppNoAccept, TargetID: mainTargetID})
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppCmdStop, TargetID: mainTargetID})
|
||||
return
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// watchAcceptTCP accepts TCP connections
|
||||
func (a *Astilectron) acceptTCP(chanAccepted chan bool) {
|
||||
for i := 0; i <= 1; i++ {
|
||||
// Accept
|
||||
var conn net.Conn
|
||||
var err error
|
||||
if conn, err = a.listener.Accept(); err != nil {
|
||||
astilog.Errorf("%s while TCP accepting", err)
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppErrorAccept, TargetID: mainTargetID})
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppCmdStop, TargetID: mainTargetID})
|
||||
return
|
||||
}
|
||||
|
||||
// We only accept the first connection which should be Astilectron, close the next one and stop
|
||||
// the app
|
||||
if i > 0 {
|
||||
astilog.Errorf("Too many TCP connections")
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppTooManyAccept, TargetID: mainTargetID})
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppCmdStop, TargetID: mainTargetID})
|
||||
conn.Close()
|
||||
return
|
||||
}
|
||||
|
||||
// Let the timer know a connection has been accepted
|
||||
chanAccepted <- true
|
||||
|
||||
// Create reader and writer
|
||||
a.writer = newWriter(conn)
|
||||
a.reader = newReader(a.dispatcher, conn)
|
||||
go a.reader.read()
|
||||
}
|
||||
}
|
||||
|
||||
// execute executes Astilectron in Electron
|
||||
func (a *Astilectron) execute() (err error) {
|
||||
// Log
|
||||
astilog.Debug("Executing...")
|
||||
|
||||
// Create command
|
||||
var ctx, _ = a.canceller.NewContext()
|
||||
var cmd = exec.CommandContext(ctx, a.paths.AppExecutable(), a.paths.AstilectronApplication(), a.listener.Addr().String())
|
||||
a.stderrWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stderr says: %s", i) })
|
||||
a.stdoutWriter = astiexec.NewStdWriter(func(i []byte) { astilog.Debugf("Stdout says: %s", i) })
|
||||
cmd.Stderr = a.stderrWriter
|
||||
cmd.Stdout = a.stdoutWriter
|
||||
|
||||
// Execute command
|
||||
if err = a.executeCmd(cmd); err != nil {
|
||||
return errors.Wrap(err, "executing cmd failed")
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// executeCmd executes the command
|
||||
func (a *Astilectron) executeCmd(cmd *exec.Cmd) (err error) {
|
||||
var e = synchronousFunc(a.canceller, a, func() {
|
||||
// Start command
|
||||
astilog.Debugf("Starting cmd %s", strings.Join(cmd.Args, " "))
|
||||
if err = cmd.Start(); err != nil {
|
||||
err = errors.Wrapf(err, "starting cmd %s failed", strings.Join(cmd.Args, " "))
|
||||
return
|
||||
}
|
||||
|
||||
// Watch command
|
||||
go a.watchCmd(cmd)
|
||||
}, EventNameAppEventReady)
|
||||
|
||||
// Update display pool
|
||||
if e.Displays != nil {
|
||||
a.displayPool.update(e.Displays)
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// watchCmd watches the cmd execution
|
||||
func (a *Astilectron) watchCmd(cmd *exec.Cmd) {
|
||||
// Wait
|
||||
cmd.Wait()
|
||||
|
||||
// Check the canceller to check whether it was a crash
|
||||
if !a.canceller.Cancelled() {
|
||||
astilog.Debug("App has crashed")
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppCrash, TargetID: mainTargetID})
|
||||
} else {
|
||||
astilog.Debug("App has closed")
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppClose, TargetID: mainTargetID})
|
||||
}
|
||||
a.dispatcher.Dispatch(Event{Name: EventNameAppCmdStop, TargetID: mainTargetID})
|
||||
}
|
||||
|
||||
// Close closes Astilectron properly
|
||||
func (a *Astilectron) Close() {
|
||||
astilog.Debug("Closing...")
|
||||
a.canceller.Cancel()
|
||||
a.dispatcher.close()
|
||||
if a.listener != nil {
|
||||
a.listener.Close()
|
||||
}
|
||||
if a.reader != nil {
|
||||
a.reader.close()
|
||||
}
|
||||
if a.stderrWriter != nil {
|
||||
a.stderrWriter.Close()
|
||||
}
|
||||
if a.stdoutWriter != nil {
|
||||
a.stdoutWriter.Close()
|
||||
}
|
||||
if a.writer != nil {
|
||||
a.writer.close()
|
||||
}
|
||||
}
|
||||
|
||||
// HandleSignals handles signals
|
||||
func (a *Astilectron) HandleSignals() {
|
||||
ch := make(chan os.Signal, 1)
|
||||
signal.Notify(ch, syscall.SIGABRT, syscall.SIGKILL, syscall.SIGINT, syscall.SIGQUIT, syscall.SIGTERM)
|
||||
go func() {
|
||||
for sig := range ch {
|
||||
astilog.Debugf("Received signal %s", sig)
|
||||
a.Stop()
|
||||
}
|
||||
}()
|
||||
}
|
||||
|
||||
// Stop orders Astilectron to stop
|
||||
func (a *Astilectron) Stop() {
|
||||
astilog.Debug("Stopping...")
|
||||
a.canceller.Cancel()
|
||||
if a.channelQuit != nil {
|
||||
close(a.channelQuit)
|
||||
a.channelQuit = nil
|
||||
}
|
||||
}
|
||||
|
||||
// Wait is a blocking pattern
|
||||
func (a *Astilectron) Wait() {
|
||||
if a.channelQuit == nil {
|
||||
return
|
||||
}
|
||||
<-a.channelQuit
|
||||
}
|
||||
|
||||
// Displays returns the displays
|
||||
func (a *Astilectron) Displays() []*Display {
|
||||
return a.displayPool.all()
|
||||
}
|
||||
|
||||
// PrimaryDisplay returns the primary display
|
||||
func (a *Astilectron) PrimaryDisplay() *Display {
|
||||
return a.displayPool.primary()
|
||||
}
|
||||
|
||||
// NewMenu creates a new app menu
|
||||
func (a *Astilectron) NewMenu(i []*MenuItemOptions) *Menu {
|
||||
return newMenu(nil, a, i, a.canceller, a.dispatcher, a.identifier, a.writer)
|
||||
}
|
||||
|
||||
// NewWindow creates a new window
|
||||
func (a *Astilectron) NewWindow(url string, o *WindowOptions) (*Window, error) {
|
||||
return newWindow(a.options, url, o, a.canceller, a.dispatcher, a.identifier, a.writer)
|
||||
}
|
||||
|
||||
// NewWindowInDisplay creates a new window in a specific display
|
||||
// This overrides the center attribute
|
||||
func (a *Astilectron) NewWindowInDisplay(d *Display, url string, o *WindowOptions) (*Window, error) {
|
||||
if o.X != nil {
|
||||
*o.X += d.Bounds().X
|
||||
} else {
|
||||
o.X = PtrInt(d.Bounds().X)
|
||||
}
|
||||
if o.Y != nil {
|
||||
*o.Y += d.Bounds().Y
|
||||
} else {
|
||||
o.Y = PtrInt(d.Bounds().Y)
|
||||
}
|
||||
return newWindow(a.options, url, o, a.canceller, a.dispatcher, a.identifier, a.writer)
|
||||
}
|
||||
|
||||
// NewTray creates a new tray
|
||||
func (a *Astilectron) NewTray(o *TrayOptions) *Tray {
|
||||
return newTray(o, a.canceller, a.dispatcher, a.identifier, a.writer)
|
||||
}
|
183
vendor/github.com/asticode/go-astilectron/astilectron_test.go
generated
vendored
Normal file
183
vendor/github.com/asticode/go-astilectron/astilectron_test.go
generated
vendored
Normal file
|
@ -0,0 +1,183 @@
|
|||
package astilectron
|
||||
|
||||
import (
|
||||
"net"
|
||||
"os"
|
||||
"sync"
|
||||
"testing"
|
||||
"time"
|
||||
|
||||
"github.com/pkg/errors"
|
||||
"github.com/stretchr/testify/assert"
|
||||
)
|
||||
|
||||
func TestAstilectron_Provision(t *testing.T) {
|
||||
// Init
|
||||
var o = Options{BaseDirectoryPath: mockedTempPath()}
|
||||
defer os.RemoveAll(o.BaseDirectoryPath)
|
||||
a, err := New(o)
|
||||
assert.NoError(t, err)
|
||||
defer a.dispatcher.close()
|
||||
go a.dispatcher.start()
|
||||
a.SetProvisioner(NewDisembedderProvisioner(mockedDisembedder, "astilectron", "electron/linux"))
|
||||
var hasStarted, hasStopped bool
|
||||
a.On(EventNameProvisionAstilectronMoved, func(e Event) bool {
|
||||
hasStarted = true
|
||||
return false
|
||||
})
|
||||
var wg = &sync.WaitGroup{}
|
||||
a.On(EventNameProvisionElectronFinished, func(e Event) bool {
|
||||
hasStopped = true
|
||||
wg.Done()
|
||||
return false
|
||||
})
|
||||
wg.Add(1)
|
||||
|
||||
// Test provision is successful and sends the correct events
|
||||
err = a.provision()
|
||||
assert.NoError(t, err)
|
||||
wg.Wait()
|
||||
assert.True(t, hasStarted)
|
||||
assert.True(t, hasStopped)
|
||||
}
|
||||
|
||||
func TestAstilectron_WatchNoAccept(t *testing.T) {
|
||||
// Init
|
||||
a, err := New(Options{})
|
||||
assert.NoError(t, err)
|
||||
defer a.dispatcher.close()
|
||||
go a.dispatcher.start()
|
||||
var isStopped bool
|
||||
var wg = &sync.WaitGroup{}
|
||||
a.On(EventNameAppCmdStop, func(e Event) bool {
|
||||
isStopped = true
|
||||
wg.Done()
|
||||
return false
|
||||
})
|
||||
c := make(chan bool)
|
||||
|
||||
// Test success
|
||||
go func() {
|
||||
time.Sleep(50 * time.Microsecond)
|
||||
c <- true
|
||||
}()
|
||||
a.watchNoAccept(time.Second, c)
|
||||
assert.False(t, isStopped)
|
||||
|
||||
// Test failure
|
||||
wg.Add(1)
|
||||
a.watchNoAccept(time.Nanosecond, c)
|
||||
wg.Wait()
|
||||
assert.True(t, isStopped)
|
||||
}
|
||||
|
||||
// mockedListener implements the net.Listener interface
|
||||
type mockedListener struct {
|
||||
c chan bool
|
||||
e chan bool
|
||||
}
|
||||
|
||||
func (l mockedListener) Accept() (net.Conn, error) {
|
||||
for {
|
||||
select {
|
||||
case <-l.c:
|
||||
return mockedConn{}, nil
|
||||
case <-l.e:
|
||||
return nil, errors.New("invalid")
|
||||
}
|
||||
}
|
||||
}
|
||||
func (l mockedListener) Close() error { return nil }
|
||||
func (l mockedListener) Addr() net.Addr { return nil }
|
||||
|
||||
// mockedConn implements the net.Conn interface
|
||||
type mockedConn struct{}
|
||||
|
||||
func (c mockedConn) Read(b []byte) (n int, err error) { return }
|
||||
func (c mockedConn) Write(b []byte) (n int, err error) { return }
|
||||
func (c mockedConn) Close() error { return nil }
|
||||
func (c mockedConn) LocalAddr() net.Addr { return nil }
|
||||
func (c mockedConn) RemoteAddr() net.Addr { return nil }
|
||||
func (c mockedConn) SetDeadline(t time.Time) error { return nil }
|
||||
func (c mockedConn) SetReadDeadline(t time.Time) error { return nil }
|
||||
func (c mockedConn) SetWriteDeadline(t time.Time) error { return nil }
|
||||
|
||||
// mockedAddr implements the net.Addr interface
|
||||
type mockedAddr struct{}
|
||||
|
||||
func (a mockedAddr) Network() string { return "" }
|
||||
func (a mockedAddr) String() string { return "" }
|
||||
|
||||
func TestAstilectron_AcceptTCP(t *testing.T) {
|
||||
// Init
|
||||
a, err := New(Options{})
|
||||
assert.NoError(t, err)
|
||||
defer a.Close()
|
||||
go a.dispatcher.start()
|
||||
var l = &mockedListener{c: make(chan bool), e: make(chan bool)}
|
||||
a.listener = l
|
||||
var isStopped bool
|
||||
var wg = &sync.WaitGroup{}
|
||||
a.On(EventNameAppCmdStop, func(e Event) bool {
|
||||
isStopped = true
|
||||
wg.Done()
|
||||
return false
|
||||
})
|
||||
c := make(chan bool)
|
||||
var isAccepted bool
|
||||
go func() {
|
||||
for {
|
||||
select {
|
||||
case <-c:
|
||||
isAccepted = true
|
||||
wg.Done()
|
||||
return
|
||||
}
|
||||
}
|
||||
}()
|
||||
go a.acceptTCP(c)
|
||||
|
||||
// Test accepted
|
||||
wg.Add(1)
|
||||
l.c <- true
|
||||
wg.Wait()
|
||||
assert.True(t, isAccepted)
|
||||
assert.False(t, isStopped)
|
||||
|
||||
// Test refused
|
||||
isAccepted = false
|
||||
wg.Add(1)
|
||||
l.c <- true
|
||||
wg.Wait()
|
||||
assert.False(t, isAccepted)
|
||||
assert.True(t, isStopped)
|
||||
|
||||
// Test error accept
|
||||
go a.acceptTCP(c)
|
||||
isStopped = false
|
||||
wg.Add(1)
|
||||
l.e <- true
|
||||
wg.Wait()
|
||||
assert.False(t, isAccepted)
|
||||
assert.True(t, isStopped)
|
||||
}
|
||||
|
||||
func TestIsValidOS(t *testing.T) {
|
||||
assert.NoError(t, validateOS("darwin"))
|
||||
assert.NoError(t, validateOS("linux"))
|
||||
assert.NoError(t, validateOS("windows"))
|
||||
assert.Error(t, validateOS("invalid"))
|
||||
}
|
||||
|
||||
func TestAstilectron_Wait(t *testing.T) {
|
||||
a, err := New(Options{})
|
||||
assert.NoError(t, err)
|
||||
a.HandleSignals()
|
||||
go func() {
|
||||
time.Sleep(20 * time.Microsecond)
|
||||
p, err := os.FindProcess(os.Getpid())
|
||||
assert.NoError(t, err)
|
||||
p.Signal(os.Interrupt)
|
||||
}()
|
||||
a.Wait()
|
||||
}
|
37
vendor/github.com/asticode/go-astilectron/bootstrap/message.go
generated
vendored
Normal file
37
vendor/github.com/asticode/go-astilectron/bootstrap/message.go
generated
vendored
Normal file
|
@ -0,0 +1,37 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"encoding/json"
|
||||
|
||||
"github.com/asticode/go-astilectron"
|
||||
"github.com/asticode/go-astilog"
|
||||
)
|
||||
|
||||
// MessageOut represents a message going out
|
||||
type MessageOut struct {
|
||||
Name string `json:"name"`
|
||||
Payload interface{} `json:"payload"`
|
||||
}
|
||||
|
||||
// MessageIn represents a message going in
|
||||
type MessageIn struct {
|
||||
Name string `json:"name"`
|
||||
Payload json.RawMessage `json:"payload"`
|
||||
}
|
||||
|
||||
// handleMessages handles messages
|
||||
func handleMessages(w *astilectron.Window, messageHandler MessageHandler) astilectron.Listener {
|
||||
return func(e astilectron.Event) (deleteListener bool) {
|
||||
// Unmarshal message
|
||||
var m MessageIn
|
||||
var err error
|
||||
if err = e.Message.Unmarshal(&m); err != nil {
|
||||
astilog.Errorf("Unmarshaling message %+v failed", *e.Message)
|
||||
return
|
||||
}
|
||||
|
||||
// Handle message
|
||||
messageHandler(w, m)
|
||||
return
|
||||
}
|
||||
}
|
45
vendor/github.com/asticode/go-astilectron/bootstrap/options.go
generated
vendored
Normal file
45
vendor/github.com/asticode/go-astilectron/bootstrap/options.go
generated
vendored
Normal file
|
@ -0,0 +1,45 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"net/http"
|
||||
|
||||
"github.com/asticode/go-astilectron"
|
||||
"github.com/julienschmidt/httprouter"
|
||||
)
|
||||
|
||||
// Options represents options
|
||||
type Options struct {
|
||||
AdaptAstilectron AdaptAstilectron
|
||||
AdaptRouter AdaptRouter
|
||||
AdaptWindow AdaptWindow
|
||||
AstilectronOptions astilectron.Options
|
||||
BaseDirectoryPath string
|
||||
CustomProvision CustomProvision
|
||||
Debug bool
|
||||
Homepage string
|
||||
MessageHandler MessageHandler
|
||||
RestoreAssets RestoreAssets
|
||||
TemplateData TemplateData
|
||||
WindowOptions *astilectron.WindowOptions
|
||||
}
|
||||
|
||||
// AdaptAstilectron is a function that adapts astilectron
|
||||
type AdaptAstilectron func(a *astilectron.Astilectron)
|
||||
|
||||
// AdaptRouter is a function that adapts the router
|
||||
type AdaptRouter func(r *httprouter.Router)
|
||||
|
||||
// AdaptWindow is a function that adapts the window
|
||||
type AdaptWindow func(w *astilectron.Window)
|
||||
|
||||
// CustomProvision is a function that executes custom provisioning
|
||||
type CustomProvision func(baseDirectoryPath string) error
|
||||
|
||||
// MessageHandler is a functions that handles messages
|
||||
type MessageHandler func(w *astilectron.Window, m MessageIn)
|
||||
|
||||
// RestoreAssets is a function that restores assets namely the go-bindata's RestoreAssets method
|
||||
type RestoreAssets func(dir, name string) error
|
||||
|
||||
// TemplateData is a function that retrieves a template's data
|
||||
type TemplateData func(name string, r *http.Request, p httprouter.Params) (d interface{}, err error)
|
38
vendor/github.com/asticode/go-astilectron/bootstrap/provisioner.go
generated
vendored
Normal file
38
vendor/github.com/asticode/go-astilectron/bootstrap/provisioner.go
generated
vendored
Normal file
|
@ -0,0 +1,38 @@
|
|||
package bootstrap
|
||||
|
||||
import (
|
||||
"os"
|
||||
"path/filepath"
|
||||
|
||||
"github.com/asticode/go-astilog"
|
||||
"github.com/pkg/errors"
|
||||
)
|
||||
|
||||
// provision provisions the resources as well as the custom provision
|
||||
func provision(baseDirectoryPath string, fnA RestoreAssets, fnP CustomProvision) (err error) {
|
||||
// Provision resources
|
||||
// TODO Handle upgrades and therefore removing the resources folder accordingly
|
||||
var pr = filepath.Join(baseDirectoryPath, "resources")
|
||||
if _, err = os.Stat(pr); os.IsNotExist(err) {
|
||||
// Restore assets
|
||||
astilog.Debugf("Restoring assets in %s", baseDirectoryPath)
|
||||
if err = fnA(baseDirectoryPath, "resources"); err != nil {
|
||||
err = errors.Wrapf(err, "restoring assets in %s failed", baseDirectoryPath)
|
||||
return
|
||||
}
|
||||
} else if err != nil {
|
||||
err = errors.Wrapf(err, "stating %s failed", pr)
|
||||
return
|
||||
} else {
|
||||
astilog.Debugf("%s already exists, skipping restoring assets...", pr)
|
||||
}
|
||||
|
||||
// Custom provision
|
||||
if fnP != nil {
|
||||
if err = fnP(baseDirectoryPath); err != nil {
|
||||
err = errors.Wrap(err, "custom provisioning failed")
|
||||
return
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user