Compare commits
23 Commits
Author | SHA1 | Date | |
---|---|---|---|
537a081551 | |||
5fa1ae684a | |||
9197e4515c | |||
27765e89ef | |||
9e71cfbbb9 | |||
a079b8a23e | |||
c5038dd4c1 | |||
f774e9a67b | |||
31ab6f15dd | |||
960214efdf | |||
f1bc1ab719 | |||
30b3f804c9 | |||
cd757112b3 | |||
0dffb86577 | |||
d2dec49dcc | |||
b038b30ec6 | |||
9c69a99f7e | |||
1330e01484 | |||
9d37b49c79 | |||
1496696694 | |||
b6a2e7ae8c | |||
2bd2bc33a2 | |||
a4204d1f07 |
110
app/app.ejs
110
app/app.ejs
@ -1,55 +1,57 @@
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-In6B8teKZQll5heMl9bS7CESTbGvuAt3VVV86BUQBDk='"/>
|
||||
<title>Helios Launcher</title>
|
||||
<script src="./assets/js/scripts/uicore.js"></script>
|
||||
<script src="./assets/js/scripts/uibinder.js"></script>
|
||||
<link type="text/css" rel="stylesheet" href="./assets/css/launcher.css">
|
||||
<style>
|
||||
body {
|
||||
/*background: url('assets/images/backgrounds/<%=bkid%>.jpg') no-repeat center center fixed;*/
|
||||
transition: background-image 1s ease;
|
||||
background-image: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAPwBwAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8VooopDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/9k=');
|
||||
background-size: cover;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
#main {
|
||||
display: none;
|
||||
height: calc(100% - 22px);
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 100%);
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
#main[overlay] {
|
||||
filter: blur(3px) contrast(0.9) brightness(1.0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body bkid="<%=bkid%>">
|
||||
<%- include('frame') %>
|
||||
<div id="main">
|
||||
<%- include('welcome') %>
|
||||
<%- include('login') %>
|
||||
<%- include('waiting') %>
|
||||
<%- include('loginOptions') %>
|
||||
<%- include('settings') %>
|
||||
<%- include('landing') %>
|
||||
</div>
|
||||
<%- include('overlay') %>
|
||||
<div id="loadingContainer">
|
||||
<div id="loadingContent">
|
||||
<div id="loadSpinnerContainer">
|
||||
<img id="loadCenterImage" src="assets/images/LoadingSeal.png">
|
||||
<img id="loadSpinnerImage" class="rotating" src="assets/images/LoadingText.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Load language
|
||||
for(let key of Object.keys(Lang.query('html'))){
|
||||
document.getElementById(key).innerHTML = Lang.query(`html.${key}`)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
<html lang="en" xmlns="http://www.w3.org/1999/xhtml">
|
||||
<head>
|
||||
<meta charset="utf-8" http-equiv="Content-Security-Policy" content="script-src 'self' 'sha256-In6B8teKZQll5heMl9bS7CESTbGvuAt3VVV86BUQBDk='"/>
|
||||
<title>Helios Launcher</title>
|
||||
<script src="./assets/js/scripts/uicore.js"></script>
|
||||
<script src="./assets/js/scripts/uibinder.js"></script>
|
||||
<link type="text/css" rel="stylesheet" href="./assets/css/launcher.css">
|
||||
<style>
|
||||
body {
|
||||
/*background: url('assets/images/backgrounds/<%=bkid%>.jpg') no-repeat center center fixed;*/
|
||||
transition: background-image 1s ease;
|
||||
background-image: url('data:image/jpeg;base64,/9j/4AAQSkZJRgABAQEAYABgAAD//gA+Q1JFQVRPUjogZ2QtanBlZyB2MS4wICh1c2luZyBJSkcgSlBFRyB2ODApLCBkZWZhdWx0IHF1YWxpdHkK/9sAQwAIBgYHBgUIBwcHCQkICgwUDQwLCwwZEhMPFB0aHx4dGhwcICQuJyAiLCMcHCg3KSwwMTQ0NB8nOT04MjwuMzQy/9sAQwEJCQkMCwwYDQ0YMiEcITIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIyMjIy/8AAEQgAPwBwAwEiAAIRAQMRAf/EAB8AAAEFAQEBAQEBAAAAAAAAAAABAgMEBQYHCAkKC//EALUQAAIBAwMCBAMFBQQEAAABfQECAwAEEQUSITFBBhNRYQcicRQygZGhCCNCscEVUtHwJDNicoIJChYXGBkaJSYnKCkqNDU2Nzg5OkNERUZHSElKU1RVVldYWVpjZGVmZ2hpanN0dXZ3eHl6g4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2drh4uPk5ebn6Onq8fLz9PX29/j5+v/EAB8BAAMBAQEBAQEBAQEAAAAAAAABAgMEBQYHCAkKC//EALURAAIBAgQEAwQHBQQEAAECdwABAgMRBAUhMQYSQVEHYXETIjKBCBRCkaGxwQkjM1LwFWJy0QoWJDThJfEXGBkaJicoKSo1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoKDhIWGh4iJipKTlJWWl5iZmqKjpKWmp6ipqrKztLW2t7i5usLDxMXGx8jJytLT1NXW19jZ2uLj5OXm5+jp6vLz9PX29/j5+v/aAAwDAQACEQMRAD8A8VooopDCiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKACiiigAooooAKKKKAP/9k=');
|
||||
background-size: cover;
|
||||
-webkit-user-select: none;
|
||||
}
|
||||
#main {
|
||||
display: none;
|
||||
height: calc(100% - 22px);
|
||||
background: linear-gradient(to top, rgba(0, 0, 0, 0.75) 0%, rgba(0, 0, 0, 0) 100%);
|
||||
width: 100%;
|
||||
position: absolute;
|
||||
z-index: 10;
|
||||
}
|
||||
#main[overlay] {
|
||||
filter: blur(3px) contrast(0.9) brightness(1.0);
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body bkid="<%=bkid%>">
|
||||
<%- include('frame') %>
|
||||
<div id="main">
|
||||
<%- include('welcome') %>
|
||||
<%- include('login') %>
|
||||
<%- include('loginOffline') %>
|
||||
<%- include('waiting') %>
|
||||
<%- include('loginOptions') %>
|
||||
<%- include('settings') %>
|
||||
<%- include('landing') %>
|
||||
<%- include('dynmap') %>
|
||||
</div>
|
||||
<%- include('overlay') %>
|
||||
<div id="loadingContainer">
|
||||
<div id="loadingContent">
|
||||
<div id="loadSpinnerContainer">
|
||||
<img id="loadCenterImage" src="assets/images/LoadingSeal.png">
|
||||
<img id="loadSpinnerImage" class="rotating" src="assets/images/LoadingText.png">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
// Load language
|
||||
for(let key of Object.keys(Lang.query('html'))){
|
||||
document.getElementById(key).innerHTML = Lang.query(`html.${key}`)
|
||||
}
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
@ -450,6 +450,79 @@ body, button {
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* loginOffline cancel button styles. */
|
||||
#loginOfflineCancelContainer {
|
||||
position: absolute;
|
||||
top: 5%;
|
||||
right: 5%;
|
||||
}
|
||||
|
||||
/* loginOffline cancel button styles. */
|
||||
#loginOfflineCancelButton {
|
||||
background: none;
|
||||
border: none;
|
||||
outline: none;
|
||||
cursor: pointer;
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
#loginOfflineCancelButton:hover #loginOfflineCancelIcon,
|
||||
#loginOfflineCancelButton:hover #loginOfflineCancelText,
|
||||
#loginOfflineCancelButton:focus #loginOfflineCancelIcon,
|
||||
#loginOfflineCancelButton:focus #loginOfflineCancelText {
|
||||
text-shadow: 0px 0px 20px white;
|
||||
}
|
||||
#loginOfflineCancelButton:hover #loginOfflineCancelIcon,
|
||||
#loginOfflineCancelButton:focus #loginOfflineCancelIcon {
|
||||
box-shadow: 0px 0px 20px white;
|
||||
}
|
||||
#loginOfflineCancelButton:active #loginOfflineCancelIcon,
|
||||
#loginOfflineCancelButton:active #loginOfflineCancelText {
|
||||
text-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75);
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
border-color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
#loginOfflineCancelButton:active #loginOfflineCancelIcon {
|
||||
box-shadow: 0px 0px 20px rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
#loginOfflineCancelButton:disabled {
|
||||
pointer-events: none;
|
||||
}
|
||||
#loginOfflineCancelButton:disabled #loginOfflineCancelIcon,
|
||||
#loginOfflineCancelButton:disabled #loginOfflineCancelText {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
border-color: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
/* The X in a circle icon for the cancel button. */
|
||||
#loginOfflineCancelIcon {
|
||||
border-radius: 50%;
|
||||
border: 1px solid white;
|
||||
box-sizing: border-box;
|
||||
height: 30px;
|
||||
width: 30px;
|
||||
font-size: 19px;
|
||||
line-height: 30px;
|
||||
margin: 0 auto;
|
||||
margin-bottom: 5px;
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
/* Text for the loginOffline cancel button. */
|
||||
#loginOfflineCancelText {
|
||||
font-size: 15px;
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/* Login content wrapper. */
|
||||
#loginContent {
|
||||
display: flex;
|
||||
@ -498,7 +571,7 @@ body, button {
|
||||
/* Header on login view. */
|
||||
#loginSubheader {
|
||||
font-family: 'Avenir Medium';
|
||||
margin-bottom: 25px;
|
||||
margin-bottom: 15px;
|
||||
font-size: 12px;
|
||||
letter-spacing: 1px;
|
||||
font-weight: bold;
|
||||
@ -518,6 +591,7 @@ body, button {
|
||||
fill: #fff;
|
||||
height: 20px;
|
||||
width: 20px;
|
||||
padding-bottom: 0.7em;
|
||||
}
|
||||
|
||||
/* Span which displays errors related to login field content. */
|
||||
@ -560,17 +634,19 @@ body, button {
|
||||
.loginField {
|
||||
font-family: 'Avenir Book';
|
||||
background: none;
|
||||
border-width: 1.5px 0px 0px 0px;
|
||||
border-width: 1px 1px 1px 1px;
|
||||
border-style: solid;
|
||||
border-radius: 5px;
|
||||
backdrop-filter: blur(5px);
|
||||
width: 250px;
|
||||
margin-bottom: 20px;
|
||||
border-color: #fff;
|
||||
margin-bottom: 15px;
|
||||
border-color: #3e3e3e;
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
font-weight: bold;
|
||||
text-align: center;
|
||||
box-sizing: border-box;
|
||||
padding: 7.5px;
|
||||
font-size: 10px;
|
||||
font-size: 14px;
|
||||
letter-spacing: 1px;
|
||||
}
|
||||
.loginField:focus {
|
||||
@ -674,6 +750,72 @@ body, button {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
/* Login Offline button styles. */
|
||||
#loginOfflineButton {
|
||||
background: none;
|
||||
font-weight: bold;
|
||||
letter-spacing: 2px;
|
||||
border: none;
|
||||
padding: 15px 5px;
|
||||
margin: 10px 0px;
|
||||
cursor: pointer;
|
||||
position: relative;
|
||||
right: -20px;
|
||||
transition: 0.5s ease;
|
||||
}
|
||||
#loginOfflineutton:disabled {
|
||||
color: rgba(255, 255, 255, 0.75);
|
||||
pointer-events: none;
|
||||
}
|
||||
#loginOfflineButton[loading] {
|
||||
color: #fff;
|
||||
}
|
||||
#loginOfflineButton:hover,
|
||||
#loginOfflineButton:focus {
|
||||
text-shadow: 0px 0px 20px #fff;
|
||||
outline: none;
|
||||
}
|
||||
#loginOfflineButton:active {
|
||||
color: #c7c7c7;
|
||||
text-shadow: 0px 0px 20px #c7c7c7;
|
||||
}
|
||||
#loginSVG {
|
||||
-webkit-transform: translate3d(0, 0, 0);
|
||||
overflow: visible;
|
||||
transform: rotate(90deg);
|
||||
margin-left: 20px;
|
||||
transition: 0.25s ease;
|
||||
width: 20px;
|
||||
height: 20px;
|
||||
}
|
||||
#loginOfflineButton:hover #loginSVG,
|
||||
#loginOfflineButton:focus #loginSVG {
|
||||
-webkit-filter: drop-shadow(0px 0px 2px #fff);
|
||||
}
|
||||
#loginOfflineButton:active #loginSVG .arrowLine {
|
||||
stroke: #c7c7c7;
|
||||
}
|
||||
#loginOfflineButton:active #loginSVG {
|
||||
-webkit-filter: drop-shadow(0px 0px 2px #c7c7c7);
|
||||
}
|
||||
#loginOfflineButton:disabled #loginSVG .arrowLine {
|
||||
stroke: rgba(255, 255, 255, 0.75);
|
||||
}
|
||||
|
||||
#loginOfflineButtonContent {
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
#loginOfflineButton .circle-loader,
|
||||
#loginOfflineButton[loading] #loginSVG {
|
||||
display: none;
|
||||
}
|
||||
#loginOfflineButton[loading] .circle-loader,
|
||||
#loginOfflineButton #loginSVG {
|
||||
display: initial;
|
||||
}
|
||||
|
||||
|
||||
.circle-loader {
|
||||
margin-left: 20px;
|
||||
@ -3964,4 +4106,67 @@ input:checked + .toggleSwitchSlider:before {
|
||||
/* Class which is applied when the spinner image is spinning. */
|
||||
.rotating {
|
||||
animation: rotating 10s linear infinite;
|
||||
}
|
||||
|
||||
|
||||
/*******************************************************************************
|
||||
* *
|
||||
* Custom patches *
|
||||
* *
|
||||
******************************************************************************/
|
||||
|
||||
|
||||
/* iframe patch for full size window. */
|
||||
#iframecontainer {
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#dynmapiframe {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
user-select: none;
|
||||
}
|
||||
|
||||
#mapsvg {
|
||||
-webkit-filter: invert(100%); /* safari 6.0 - 9.0 */
|
||||
filter: invert(100%);
|
||||
transition: 0.25s ease;
|
||||
}
|
||||
|
||||
/* Map icon hover effect */
|
||||
#newsButton:hover #mapsvg,
|
||||
#newsButton:focus #mapsvg {
|
||||
filter:invert(100%) drop-shadow(0 0 0.75rem white);
|
||||
}
|
||||
|
||||
/* Return from map button */
|
||||
.FloatingButtonContainer {
|
||||
position: absolute;
|
||||
margin-left: auto;
|
||||
margin-right: auto;
|
||||
left: 22em;
|
||||
right: 0;
|
||||
text-align: center;
|
||||
}
|
||||
|
||||
/* Return from map button style */
|
||||
#dynmapDoneButton {
|
||||
background-color: #222222;
|
||||
width: 100px;
|
||||
border-radius: 0px 0px 10px 10px;
|
||||
border-color: #333333;
|
||||
border: solid;
|
||||
border-width: 0px 1px 1px 1px;
|
||||
}
|
||||
|
||||
#dynmapDoneButtonText {
|
||||
color: white;
|
||||
font-weight: 900;
|
||||
letter-spacing: 2px;
|
||||
text-shadow: 0px 0px 0px #bebcbb;
|
||||
font-size: 11px;
|
||||
line-height: 30px;
|
||||
transition: 0.25s ease;
|
||||
display: flex;
|
||||
justify-content: center;
|
||||
}
|
298
app/assets/distribution.json
Normal file
298
app/assets/distribution.json
Normal file
@ -0,0 +1,298 @@
|
||||
{
|
||||
"version": "1.0.0",
|
||||
"discord": {
|
||||
"clientId": "385581240906022916",
|
||||
"smallImageText": "WesterosCraft",
|
||||
"smallImageKey": "seal-circle"
|
||||
},
|
||||
"java": {
|
||||
"oracle": "http://www.oracle.com/technetwork/java/javase/downloads/jre8-downloads-2133155.html"
|
||||
},
|
||||
"rss": "https://westeroscraft.com/articles/index.rss",
|
||||
"servers": [
|
||||
{
|
||||
"id": "SkirdaTesting-1.12.2",
|
||||
"name": "Skirda Test Server",
|
||||
"description": "Сплошные баги блять",
|
||||
"icon": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/server-prod.png",
|
||||
"version": "4.6.5",
|
||||
"address": "192.168.88.228:35012",
|
||||
"minecraftVersion": "1.12.2",
|
||||
"discord": {
|
||||
"shortId": "Skirda Minecraft Server",
|
||||
"largeImageText": "Skirda 1.12.2 Minecraft Server",
|
||||
"largeImageKey": "skirda-testing"
|
||||
},
|
||||
"mainServer": false,
|
||||
"autoconnect": true,
|
||||
"modules": [
|
||||
{
|
||||
"id": "net.minecraftforge:forge:1.12.2-14.23.5.2847",
|
||||
"name": "Minecraft Forge",
|
||||
"type": "ForgeHosted",
|
||||
"artifact": {
|
||||
"size": 4884700,
|
||||
"MD5": "90734a5a713e24902d24c45c15caa42c",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/forge-1.12.2-14.23.5.2847-universal.jar"
|
||||
},
|
||||
"subModules": [
|
||||
{
|
||||
"id": "net.minecraft:launchwrapper:1.12",
|
||||
"name": "Mojang (LaunchWrapper)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 32999,
|
||||
"MD5": "934b2d91c7c5be4a49577c9e6b40e8da",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/launchwrapper-1.12.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.ow2.asm:asm-all:5.2",
|
||||
"name": "Mojang (ASM)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 247787,
|
||||
"MD5": "f5ad16c7f0338b541978b0430d51dc83",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/asm-all-5.2.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "jline:jline:2.13",
|
||||
"name": "Mojang (jline)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 248566,
|
||||
"MD5": "f251ba666cccb260ff7215b2cbeee8d4",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jline-2.13.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-library:2.11.1@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-library)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 1474672,
|
||||
"MD5": "379c15c4f724421c6d5d7aecedaf87a6",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-library-2.11.1.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-compiler:2.11.1@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-compiler)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 3076920,
|
||||
"MD5": "7d89e952f2d5c74577310cd2c28e3f20",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-compiler-2.11.1.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-actors-migration_2.11:1.1.0@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-actors-migration)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 21324,
|
||||
"MD5": "04e3428b2600ace33c7ae2bf1f6c0a4c",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-actors-migration_2.11-1.1.0.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang.plugins:scala-continuations-library_2.11:1.0.2@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-continuations-library)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 7956,
|
||||
"MD5": "ed9b1d27aba8ac4090a3749c4dfc895a",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-library_2.11-1.0.2.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang.plugins:scala-continuations-plugin_2.11.1:1.0.2@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-continuations-plugin)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 46140,
|
||||
"MD5": "a8232db22a72a981de6b1399eb86dff7",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-continuations-plugin_2.11.1-1.0.2.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-parser-combinators_2.11:1.0.1@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-parser-combinators)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 85568,
|
||||
"MD5": "2e50a7df17680daadacca69f07f8a16d",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-parser-combinators_2.11-1.0.1.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-reflect:2.11.1@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-reflect)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 1070312,
|
||||
"MD5": "84e5dc81c10e2bd74c579c9d0332fdd9",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-reflect-2.11.1.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-swing_2.11:1.0.1",
|
||||
"name": "Minecraft Forge (scala-swing)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 736795,
|
||||
"MD5": "1d360289e697022a3f57abaad344b28f",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-swing_2.11-1.0.1.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.scala-lang:scala-xml_2.11:1.0.2@jar.pack.xz",
|
||||
"name": "Minecraft Forge (scala-xml)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 217812,
|
||||
"MD5": "cc891b094a4c32dedc56bfefe9b072ff",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/scala-xml_2.11-1.0.2.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "com.typesafe.akka:akka-actor_2.11:2.3.3@jar.pack.xz",
|
||||
"name": "Minecraft Forge (akka-actor)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 746612,
|
||||
"MD5": "25cb22c3078e9fb3f7a861c912924862",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/akka-actor_2.11-2.3.3.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "com.typesafe:config:1.2.1@jar.pack.xz",
|
||||
"name": "Minecraft Forge (typesafe-config)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 56636,
|
||||
"MD5": "10ec4ccabc4e68aac9cf87165ead5d7d",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/config-1.2.1.jar.pack.xz"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "lzma:lzma:0.0.1",
|
||||
"name": "Mojang (LZMA)",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 5762,
|
||||
"MD5": "a3e3c3186e41c4a1a3027ba2bb23cdc6",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/lzma-0.0.1.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "net.sf.trove4j:trove4j:3.0.3",
|
||||
"name": "Trove4J",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 2523218,
|
||||
"MD5": "8fc4d4e0129244f9fd39650c5f30feb2",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/trove4j-3.0.3.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "java3d:vecmath:1.5.2",
|
||||
"name": "Vecmath",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 318956,
|
||||
"MD5": "e5d2b7f46c4800a32f62ce75676a5710",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/vecmath-1.5.2.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "net.sf.jopt-simple:jopt-simple:5.0.3",
|
||||
"name": "Jopt-simple",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 78175,
|
||||
"MD5": "0a5ec84e23df9d7cfb4063bc55f2744c",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/jopt-simple-5.0.3.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "org.apache.maven:maven-artifact:3.5.3",
|
||||
"name": "maven-artifact",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 54961,
|
||||
"MD5": "7741ebf29690ee7d9dde9cf4376347fc",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/maven-artifact-3.5.3.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "net.minecraftforge:MercuriusUpdater:1.12.2",
|
||||
"name": "MercuriusUpdater",
|
||||
"type": "Library",
|
||||
"artifact": {
|
||||
"size": 15098,
|
||||
"MD5": "6eb9e61097bee3103a2fdc42746b76a4",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/1.12.2/MercuriusUpdater-1.12.2.jar"
|
||||
}
|
||||
}
|
||||
]
|
||||
},
|
||||
{
|
||||
"id": "net.optifine:optifine:1.12.2_HD_U_F5",
|
||||
"name": "Optifine",
|
||||
"type": "ForgeMod",
|
||||
"artifact": {
|
||||
"size": 2598821,
|
||||
"MD5": "043ac1db6f7441ea4cf31bcb621aff0b",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/OptiFine.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "mezz:jei:1.12.2-4.14.3.242",
|
||||
"name": "JustEnoughItems",
|
||||
"type": "ForgeMod",
|
||||
"artifact": {
|
||||
"size": 620682,
|
||||
"MD5": "ae6d0e6e873ef6c20f41097dc7fee8c6",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/jei.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "xaeros:minimap:1.12.2-20.15.0",
|
||||
"name": "XaerosMinimap",
|
||||
"type": "ForgeMod",
|
||||
"required": {
|
||||
"value": false
|
||||
},
|
||||
"artifact": {
|
||||
"size": 528849,
|
||||
"MD5": "cc12cfe20febd1404345f5339e522cda",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/mods/Xaeros_Minimap.jar"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "options.txt",
|
||||
"name": "Default Client Options",
|
||||
"type": "File",
|
||||
"artifact": {
|
||||
"size": 1973,
|
||||
"path": "options.txt",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/files/options-1.12.2.txt"
|
||||
}
|
||||
},
|
||||
{
|
||||
"id": "servers.dat",
|
||||
"name": "Saved Client Servers",
|
||||
"type": "File",
|
||||
"artifact": {
|
||||
"size": 84,
|
||||
"MD5": "71d99e229d7d2b8d2a6423e46832a4b8",
|
||||
"path": "servers.dat",
|
||||
"url": "http://mc.westeroscraft.com/WesterosCraftLauncher/prod-1.12.2/servers.dat"
|
||||
}
|
||||
}
|
||||
]
|
||||
}
|
||||
]
|
||||
}
|
@ -15,6 +15,7 @@ const { RestResponseStatus } = require('helios-core/common')
|
||||
const { MojangRestAPI, mojangErrorDisplayable, MojangErrorCode } = require('helios-core/mojang')
|
||||
const { MicrosoftAuth, microsoftErrorDisplayable, MicrosoftErrorCode } = require('helios-core/microsoft')
|
||||
const { AZURE_CLIENT_ID } = require('./ipcconstants')
|
||||
const { async } = require('node-stream-zip')
|
||||
|
||||
const log = LoggerUtil.getLogger('AuthManager')
|
||||
|
||||
@ -57,6 +58,11 @@ exports.addMojangAccount = async function(username, password) {
|
||||
}
|
||||
}
|
||||
|
||||
exports.addOfflineAccount = async function(usernameOffline){
|
||||
//TODO: check for forbidden symbols and lenght!!
|
||||
ConfigManager.addOfflineAccount(usernameOffline)
|
||||
}
|
||||
|
||||
const AUTH_MODE = { FULL: 0, MS_REFRESH: 1, MC_REFRESH: 2 }
|
||||
|
||||
/**
|
||||
@ -181,6 +187,17 @@ exports.removeMojangAccount = async function(uuid){
|
||||
}
|
||||
}
|
||||
|
||||
exports.removeOfflineAccount = async function(uuid){
|
||||
try {
|
||||
ConfigManager.removeAuthAccount(uuid)
|
||||
ConfigManager.save()
|
||||
return Promise.resolve()
|
||||
} catch (err){
|
||||
log.error('Error while removing account', err)
|
||||
return Promise.reject(err)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Remove a Microsoft account. It is expected that the caller will invoke the OAuth logout
|
||||
* through the ipc renderer.
|
||||
|
@ -1,3 +1,4 @@
|
||||
const { uuid } = require('discord-rpc-patch/src/util')
|
||||
const fs = require('fs-extra')
|
||||
const os = require('os')
|
||||
const path = require('path')
|
||||
@ -353,6 +354,19 @@ exports.addMojangAuthAccount = function(uuid, accessToken, username, displayName
|
||||
return config.authenticationDatabase[uuid]
|
||||
}
|
||||
|
||||
exports.addOfflineAccount = function(usernameOffline){
|
||||
fake_uuid = usernameOffline
|
||||
config.selectedAccount = fake_uuid
|
||||
accessToken = ""
|
||||
config.authenticationDatabase[fake_uuid] = {
|
||||
type: 'offline',
|
||||
accessToken,
|
||||
username: usernameOffline.trim(),
|
||||
uuid: fake_uuid.trim(),
|
||||
displayName: usernameOffline.trim()
|
||||
}
|
||||
return config.authenticationDatabase[fake_uuid]
|
||||
}
|
||||
/**
|
||||
* Update the tokens of an authenticated microsoft account.
|
||||
*
|
||||
|
@ -537,7 +537,8 @@ exports.pullRemote = function(){
|
||||
return exports.pullLocal()
|
||||
}
|
||||
return new Promise((resolve, reject) => {
|
||||
const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
|
||||
//const distroURL = 'http://mc.westeroscraft.com/WesterosCraftLauncher/distribution.json'
|
||||
const distroURL = "https://skirda.gregbrzezinski.com/distribution.json"
|
||||
//const distroURL = 'https://gist.githubusercontent.com/dscalzi/53b1ba7a11d26a5c353f9d5ae484b71b/raw/'
|
||||
const opts = {
|
||||
url: distroURL,
|
||||
|
3
app/assets/js/scripts/dynmap.js
Normal file
3
app/assets/js/scripts/dynmap.js
Normal file
@ -0,0 +1,3 @@
|
||||
dynmapDoneButton.addEventListener('click', () => {
|
||||
switchView(getCurrentView(), VIEWS.landing)
|
||||
})
|
@ -108,6 +108,7 @@ document.getElementById('launch_button').addEventListener('click', function(e){
|
||||
}
|
||||
})
|
||||
|
||||
|
||||
// Bind settings button
|
||||
document.getElementById('settingsMediaButton').onclick = (e) => {
|
||||
prepareSettings()
|
||||
@ -325,7 +326,7 @@ function asyncSystemScan(mcVersion, launchAfter = true){
|
||||
// Show this information to the user.
|
||||
setOverlayContent(
|
||||
'No Compatible<br>Java Installation Found',
|
||||
'In order to join WesterosCraft, you need a 64-bit installation of Java 8. Would you like us to install a copy?',
|
||||
'In order to join Skirda, you need a 64-bit installation of Java 8. Would you like us to install a copy?',
|
||||
'Install Java',
|
||||
'Install Manually'
|
||||
)
|
||||
@ -484,12 +485,12 @@ function dlAsync(login = true){
|
||||
// Login parameter is temporary for debug purposes. Allows testing the validation/downloads without
|
||||
// launching the game.
|
||||
|
||||
if(login) {
|
||||
/* if(login) {
|
||||
if(ConfigManager.getSelectedAccount() == null){
|
||||
loggerLanding.error('You must be logged into an account.')
|
||||
return
|
||||
}
|
||||
}
|
||||
}*/
|
||||
|
||||
setLaunchDetails('Please wait..')
|
||||
toggleLaunchArea(true)
|
||||
@ -808,6 +809,8 @@ function slide_(up){
|
||||
//date.toLocaleDateString('en-US', {month: 'short', day: 'numeric', year: 'numeric', hour: 'numeric', minute: 'numeric'})
|
||||
//landingContainer.style.background = 'rgba(29, 29, 29, 0.55)'
|
||||
landingContainer.style.background = 'rgba(0, 0, 0, 0.50)'
|
||||
//Frame bar dimming (map patch)
|
||||
frameBar.style.background = 'rgba(0, 0, 0)'
|
||||
setTimeout(() => {
|
||||
if(newsGlideCount === 1){
|
||||
lCLCenter.style.transition = 'none'
|
||||
@ -820,6 +823,8 @@ function slide_(up){
|
||||
newsGlideCount--
|
||||
}, 2000)
|
||||
landingContainer.style.background = null
|
||||
//Frame bar dimming revert (map patch)
|
||||
frameBar.style.background = 'rgba(0, 0, 0, 0.50)'
|
||||
lCLCenter.style.transition = null
|
||||
newsBtn.style.transition = null
|
||||
newsContainer.style.top = '100%'
|
||||
@ -833,8 +838,9 @@ function slide_(up){
|
||||
|
||||
// Bind news button.
|
||||
document.getElementById('newsButton').onclick = () => {
|
||||
switchView(getCurrentView(), VIEWS.dynmap, 500, 500)
|
||||
// Toggle tabbing.
|
||||
if(newsActive){
|
||||
/*if(newsActive){
|
||||
$('#landingContainer *').removeAttr('tabindex')
|
||||
$('#newsContainer *').attr('tabindex', '-1')
|
||||
} else {
|
||||
@ -846,9 +852,9 @@ document.getElementById('newsButton').onclick = () => {
|
||||
ConfigManager.setNewsCacheDismissed(true)
|
||||
ConfigManager.save()
|
||||
}
|
||||
}
|
||||
slide_(!newsActive)
|
||||
newsActive = !newsActive
|
||||
}*/
|
||||
//slide_(!newsActive)
|
||||
//newsActive = !newsActive
|
||||
}
|
||||
|
||||
// Array to store article meta.
|
||||
|
@ -1,239 +1,239 @@
|
||||
/**
|
||||
* Script for login.ejs
|
||||
*/
|
||||
// Validation Regexes.
|
||||
const validUsername = /^[a-zA-Z0-9_]{1,16}$/
|
||||
const basicEmail = /^\S+@\S+\.\S+$/
|
||||
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
|
||||
|
||||
// Login Elements
|
||||
const loginCancelContainer = document.getElementById('loginCancelContainer')
|
||||
const loginCancelButton = document.getElementById('loginCancelButton')
|
||||
const loginEmailError = document.getElementById('loginEmailError')
|
||||
const loginUsername = document.getElementById('loginUsername')
|
||||
const loginPasswordError = document.getElementById('loginPasswordError')
|
||||
const loginPassword = document.getElementById('loginPassword')
|
||||
const checkmarkContainer = document.getElementById('checkmarkContainer')
|
||||
const loginRememberOption = document.getElementById('loginRememberOption')
|
||||
const loginButton = document.getElementById('loginButton')
|
||||
const loginForm = document.getElementById('loginForm')
|
||||
|
||||
// Control variables.
|
||||
let lu = false, lp = false
|
||||
|
||||
const loggerLogin = LoggerUtil1('%c[Login]', 'color: #000668; font-weight: bold')
|
||||
|
||||
|
||||
/**
|
||||
* Show a login error.
|
||||
*
|
||||
* @param {HTMLElement} element The element on which to display the error.
|
||||
* @param {string} value The error text.
|
||||
*/
|
||||
function showError(element, value){
|
||||
element.innerHTML = value
|
||||
element.style.opacity = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Shake a login error to add emphasis.
|
||||
*
|
||||
* @param {HTMLElement} element The element to shake.
|
||||
*/
|
||||
function shakeError(element){
|
||||
if(element.style.opacity == 1){
|
||||
element.classList.remove('shake')
|
||||
void element.offsetWidth
|
||||
element.classList.add('shake')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an email field is neither empty nor invalid.
|
||||
*
|
||||
* @param {string} value The email value.
|
||||
*/
|
||||
function validateEmail(value){
|
||||
if(value){
|
||||
if(!basicEmail.test(value) && !validUsername.test(value)){
|
||||
showError(loginEmailError, Lang.queryJS('login.error.invalidValue'))
|
||||
loginDisabled(true)
|
||||
lu = false
|
||||
} else {
|
||||
loginEmailError.style.opacity = 0
|
||||
lu = true
|
||||
if(lp){
|
||||
loginDisabled(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lu = false
|
||||
showError(loginEmailError, Lang.queryJS('login.error.requiredValue'))
|
||||
loginDisabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the password field is not empty.
|
||||
*
|
||||
* @param {string} value The password value.
|
||||
*/
|
||||
function validatePassword(value){
|
||||
if(value){
|
||||
loginPasswordError.style.opacity = 0
|
||||
lp = true
|
||||
if(lu){
|
||||
loginDisabled(false)
|
||||
}
|
||||
} else {
|
||||
lp = false
|
||||
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
|
||||
loginDisabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Emphasize errors with shake when focus is lost.
|
||||
loginUsername.addEventListener('focusout', (e) => {
|
||||
validateEmail(e.target.value)
|
||||
shakeError(loginEmailError)
|
||||
})
|
||||
loginPassword.addEventListener('focusout', (e) => {
|
||||
validatePassword(e.target.value)
|
||||
shakeError(loginPasswordError)
|
||||
})
|
||||
|
||||
// Validate input for each field.
|
||||
loginUsername.addEventListener('input', (e) => {
|
||||
validateEmail(e.target.value)
|
||||
})
|
||||
loginPassword.addEventListener('input', (e) => {
|
||||
validatePassword(e.target.value)
|
||||
})
|
||||
|
||||
/**
|
||||
* Enable or disable the login button.
|
||||
*
|
||||
* @param {boolean} v True to enable, false to disable.
|
||||
*/
|
||||
function loginDisabled(v){
|
||||
if(loginButton.disabled !== v){
|
||||
loginButton.disabled = v
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable loading elements.
|
||||
*
|
||||
* @param {boolean} v True to enable, false to disable.
|
||||
*/
|
||||
function loginLoading(v){
|
||||
if(v){
|
||||
loginButton.setAttribute('loading', v)
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn'))
|
||||
} else {
|
||||
loginButton.removeAttribute('loading')
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login'))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable login form.
|
||||
*
|
||||
* @param {boolean} v True to enable, false to disable.
|
||||
*/
|
||||
function formDisabled(v){
|
||||
loginDisabled(v)
|
||||
loginCancelButton.disabled = v
|
||||
loginUsername.disabled = v
|
||||
loginPassword.disabled = v
|
||||
if(v){
|
||||
checkmarkContainer.setAttribute('disabled', v)
|
||||
} else {
|
||||
checkmarkContainer.removeAttribute('disabled')
|
||||
}
|
||||
loginRememberOption.disabled = v
|
||||
}
|
||||
|
||||
let loginViewOnSuccess = VIEWS.landing
|
||||
let loginViewOnCancel = VIEWS.settings
|
||||
let loginViewCancelHandler
|
||||
|
||||
function loginCancelEnabled(val){
|
||||
if(val){
|
||||
$(loginCancelContainer).show()
|
||||
} else {
|
||||
$(loginCancelContainer).hide()
|
||||
}
|
||||
}
|
||||
|
||||
loginCancelButton.onclick = (e) => {
|
||||
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
|
||||
loginUsername.value = ''
|
||||
loginPassword.value = ''
|
||||
loginCancelEnabled(false)
|
||||
if(loginViewCancelHandler != null){
|
||||
loginViewCancelHandler()
|
||||
loginViewCancelHandler = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Disable default form behavior.
|
||||
loginForm.onsubmit = () => { return false }
|
||||
|
||||
// Bind login button behavior.
|
||||
loginButton.addEventListener('click', () => {
|
||||
// Disable form.
|
||||
formDisabled(true)
|
||||
|
||||
// Show loading stuff.
|
||||
loginLoading(true)
|
||||
|
||||
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
||||
updateSelectedAccount(value)
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
||||
$('.circle-loader').toggleClass('load-complete')
|
||||
$('.checkmark').toggle()
|
||||
setTimeout(() => {
|
||||
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => {
|
||||
// Temporary workaround
|
||||
if(loginViewOnSuccess === VIEWS.settings){
|
||||
prepareSettings()
|
||||
}
|
||||
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
||||
loginCancelEnabled(false) // Reset this for good measure.
|
||||
loginViewCancelHandler = null // Reset this for good measure.
|
||||
loginUsername.value = ''
|
||||
loginPassword.value = ''
|
||||
$('.circle-loader').toggleClass('load-complete')
|
||||
$('.checkmark').toggle()
|
||||
loginLoading(false)
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
|
||||
formDisabled(false)
|
||||
})
|
||||
}, 1000)
|
||||
}).catch((displayableError) => {
|
||||
loginLoading(false)
|
||||
|
||||
let actualDisplayableError
|
||||
if(isDisplayableError(displayableError)) {
|
||||
msftLoginLogger.error('Error while logging in.', displayableError)
|
||||
actualDisplayableError = displayableError
|
||||
} else {
|
||||
// Uh oh.
|
||||
msftLoginLogger.error('Unhandled error during login.', displayableError)
|
||||
actualDisplayableError = {
|
||||
title: 'Unknown Error During Login',
|
||||
desc: 'An unknown error has occurred. Please see the console for details.'
|
||||
}
|
||||
}
|
||||
|
||||
setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain'))
|
||||
setOverlayHandler(() => {
|
||||
formDisabled(false)
|
||||
toggleOverlay(false)
|
||||
})
|
||||
toggleOverlay(true)
|
||||
})
|
||||
|
||||
/**
|
||||
* Script for login.ejs
|
||||
*/
|
||||
// Validation Regexes.
|
||||
const validUsername = /^[a-zA-Z0-9_]{1,16}$/
|
||||
const basicEmail = /^\S+@\S+\.\S+$/
|
||||
//const validEmail = /^(([^<>()\[\]\.,;:\s@\"]+(\.[^<>()\[\]\.,;:\s@\"]+)*)|(\".+\"))@(([^<>()[\]\.,;:\s@\"]+\.)+[^<>()[\]\.,;:\s@\"]{2,})$/i
|
||||
|
||||
// Login Elements
|
||||
const loginCancelContainer = document.getElementById('loginCancelContainer')
|
||||
const loginCancelButton = document.getElementById('loginCancelButton')
|
||||
const loginEmailError = document.getElementById('loginEmailError')
|
||||
const loginUsername = document.getElementById('loginUsername')
|
||||
const loginPasswordError = document.getElementById('loginPasswordError')
|
||||
const loginPassword = document.getElementById('loginPassword')
|
||||
const checkmarkContainer = document.getElementById('checkmarkContainer')
|
||||
const loginRememberOption = document.getElementById('loginRememberOption')
|
||||
const loginButton = document.getElementById('loginButton')
|
||||
const loginForm = document.getElementById('loginForm')
|
||||
|
||||
// Control variables.
|
||||
let lu = false, lp = false
|
||||
|
||||
const loggerLogin = LoggerUtil1('%c[Login]', 'color: #000668; font-weight: bold')
|
||||
|
||||
|
||||
/**
|
||||
* Show a login error.
|
||||
*
|
||||
* @param {HTMLElement} element The element on which to display the error.
|
||||
* @param {string} value The error text.
|
||||
*/
|
||||
function showError(element, value){
|
||||
element.innerHTML = value
|
||||
element.style.opacity = 1
|
||||
}
|
||||
|
||||
/**
|
||||
* Shake a login error to add emphasis.
|
||||
*
|
||||
* @param {HTMLElement} element The element to shake.
|
||||
*/
|
||||
function shakeError(element){
|
||||
if(element.style.opacity == 1){
|
||||
element.classList.remove('shake')
|
||||
void element.offsetWidth
|
||||
element.classList.add('shake')
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that an email field is neither empty nor invalid.
|
||||
*
|
||||
* @param {string} value The email value.
|
||||
*/
|
||||
function validateEmail(value){
|
||||
if(value){
|
||||
if(!basicEmail.test(value) && !validUsername.test(value)){
|
||||
showError(loginEmailError, Lang.queryJS('login.error.invalidValue'))
|
||||
loginDisabled(true)
|
||||
lu = false
|
||||
} else {
|
||||
loginEmailError.style.opacity = 0
|
||||
lu = true
|
||||
if(lp){
|
||||
loginDisabled(false)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
lu = false
|
||||
showError(loginEmailError, Lang.queryJS('login.error.requiredValue'))
|
||||
loginDisabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Validate that the password field is not empty.
|
||||
*
|
||||
* @param {string} value The password value.
|
||||
*/
|
||||
function validatePassword(value){
|
||||
if(value){
|
||||
loginPasswordError.style.opacity = 0
|
||||
lp = true
|
||||
if(lu){
|
||||
loginDisabled(false)
|
||||
}
|
||||
} else {
|
||||
lp = false
|
||||
showError(loginPasswordError, Lang.queryJS('login.error.invalidValue'))
|
||||
loginDisabled(true)
|
||||
}
|
||||
}
|
||||
|
||||
// Emphasize errors with shake when focus is lost.
|
||||
loginUsername.addEventListener('focusout', (e) => {
|
||||
validateEmail(e.target.value)
|
||||
shakeError(loginEmailError)
|
||||
})
|
||||
loginPassword.addEventListener('focusout', (e) => {
|
||||
validatePassword(e.target.value)
|
||||
shakeError(loginPasswordError)
|
||||
})
|
||||
|
||||
// Validate input for each field.
|
||||
loginUsername.addEventListener('input', (e) => {
|
||||
validateEmail(e.target.value)
|
||||
})
|
||||
loginPassword.addEventListener('input', (e) => {
|
||||
validatePassword(e.target.value)
|
||||
})
|
||||
|
||||
/**
|
||||
* Enable or disable the login button.
|
||||
*
|
||||
* @param {boolean} v True to enable, false to disable.
|
||||
*/
|
||||
function loginDisabled(v){
|
||||
if(loginButton.disabled !== v){
|
||||
loginButton.disabled = v
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable loading elements.
|
||||
*
|
||||
* @param {boolean} v True to enable, false to disable.
|
||||
*/
|
||||
function loginLoading(v){
|
||||
if(v){
|
||||
loginButton.setAttribute('loading', v)
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.login'), Lang.queryJS('login.loggingIn'))
|
||||
} else {
|
||||
loginButton.removeAttribute('loading')
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.login'))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Enable or disable login form.
|
||||
*
|
||||
* @param {boolean} v True to enable, false to disable.
|
||||
*/
|
||||
function formDisabled(v){
|
||||
loginDisabled(v)
|
||||
loginCancelButton.disabled = v
|
||||
loginUsername.disabled = v
|
||||
loginPassword.disabled = v
|
||||
if(v){
|
||||
checkmarkContainer.setAttribute('disabled', v)
|
||||
} else {
|
||||
checkmarkContainer.removeAttribute('disabled')
|
||||
}
|
||||
loginRememberOption.disabled = v
|
||||
}
|
||||
|
||||
let loginViewOnSuccess = VIEWS.landing
|
||||
let loginViewOnCancel = VIEWS.settings
|
||||
let loginViewCancelHandler
|
||||
|
||||
function loginCancelEnabled(val){
|
||||
if(val){
|
||||
$(loginCancelContainer).show()
|
||||
} else {
|
||||
$(loginCancelContainer).hide()
|
||||
}
|
||||
}
|
||||
|
||||
loginCancelButton.onclick = (e) => {
|
||||
switchView(getCurrentView(), loginViewOnCancel, 500, 500, () => {
|
||||
loginUsername.value = ''
|
||||
loginPassword.value = ''
|
||||
loginCancelEnabled(false)
|
||||
if(loginViewCancelHandler != null){
|
||||
loginViewCancelHandler()
|
||||
loginViewCancelHandler = null
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
// Disable default form behavior.
|
||||
loginForm.onsubmit = () => { return false }
|
||||
|
||||
// Bind login button behavior.
|
||||
loginButton.addEventListener('click', () => {
|
||||
// Disable form.
|
||||
formDisabled(true)
|
||||
|
||||
// Show loading stuff.
|
||||
loginLoading(true)
|
||||
|
||||
AuthManager.addMojangAccount(loginUsername.value, loginPassword.value).then((value) => {
|
||||
updateSelectedAccount(value)
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.loggingIn'), Lang.queryJS('login.success'))
|
||||
$('.circle-loader').toggleClass('load-complete')
|
||||
$('.checkmark').toggle()
|
||||
setTimeout(() => {
|
||||
switchView(VIEWS.login, loginViewOnSuccess, 500, 500, () => {
|
||||
// Temporary workaround
|
||||
if(loginViewOnSuccess === VIEWS.settings){
|
||||
prepareSettings()
|
||||
}
|
||||
loginViewOnSuccess = VIEWS.landing // Reset this for good measure.
|
||||
loginCancelEnabled(false) // Reset this for good measure.
|
||||
loginViewCancelHandler = null // Reset this for good measure.
|
||||
loginUsername.value = ''
|
||||
loginPassword.value = ''
|
||||
$('.circle-loader').toggleClass('load-complete')
|
||||
$('.checkmark').toggle()
|
||||
loginLoading(false)
|
||||
loginButton.innerHTML = loginButton.innerHTML.replace(Lang.queryJS('login.success'), Lang.queryJS('login.login'))
|
||||
formDisabled(false)
|
||||
})
|
||||
}, 1000)
|
||||
}).catch((displayableError) => {
|
||||
loginLoading(false)
|
||||
|
||||
let actualDisplayableError
|
||||
if(isDisplayableError(displayableError)) {
|
||||
msftLoginLogger.error('Error while logging in.', displayableError)
|
||||
actualDisplayableError = displayableError
|
||||
} else {
|
||||
// Uh oh.
|
||||
msftLoginLogger.error('Unhandled error during login.', displayableError)
|
||||
actualDisplayableError = {
|
||||
title: 'Unknown Error During Login',
|
||||
desc: 'An unknown error has occurred. Please see the console for details.'
|
||||
}
|
||||
}
|
||||
|
||||
setOverlayContent(actualDisplayableError.title, actualDisplayableError.desc, Lang.queryJS('login.tryAgain'))
|
||||
setOverlayHandler(() => {
|
||||
formDisabled(false)
|
||||
toggleOverlay(false)
|
||||
})
|
||||
toggleOverlay(true)
|
||||
})
|
||||
|
||||
})
|
39
app/assets/js/scripts/loginOffline.js
Normal file
39
app/assets/js/scripts/loginOffline.js
Normal file
@ -0,0 +1,39 @@
|
||||
const loggerOfflineLogin = LoggerUtil1('%c[LoginOffline]', 'color: #000668; font-weight: bold')
|
||||
|
||||
const loginOfflineButton = document.getElementById('loginOfflineButton')
|
||||
const loginOfflineCancelContainer = document.getElementById('loginOfflineCancelContainer')
|
||||
const loginOfflineCancelButton = document.getElementById('loginOfflineCancelButton')
|
||||
|
||||
function loginOfflineDisabled(v){
|
||||
if(loginOfflineButton.disabled !== v){
|
||||
loginOfflineButton.disabled = v
|
||||
}
|
||||
}
|
||||
|
||||
function formOfflineDisabled(v){
|
||||
loginOfflineDisabled(v)
|
||||
loginOfflineUsername.disabled = v
|
||||
}
|
||||
|
||||
|
||||
|
||||
loginOfflineButton.addEventListener('click', () => {
|
||||
formOfflineDisabled(true)
|
||||
AuthManager.addOfflineAccount(loginOfflineUsername.value).then((value) =>{
|
||||
switchView(VIEWS.loginOffline, VIEWS.landing, 500, 500)
|
||||
|
||||
})
|
||||
loginOfflineUsername = ''
|
||||
})
|
||||
|
||||
loginOfflineCancelButton.addEventListener('click', () => {
|
||||
if (Object.keys(ConfigManager.getAuthAccounts()).length === 0) {
|
||||
loginOfflineUsername.value = ''
|
||||
switchView(VIEWS.loginOffline, VIEWS.loginOptions, 500, 500)
|
||||
}
|
||||
else
|
||||
{
|
||||
loginOfflineUsername.value = ''
|
||||
switchView(VIEWS.loginOffline, VIEWS.landing, 500, 500)
|
||||
}
|
||||
})
|
@ -1,50 +1,45 @@
|
||||
const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer')
|
||||
const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft')
|
||||
const loginOptionMojang = document.getElementById('loginOptionMojang')
|
||||
const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton')
|
||||
|
||||
let loginOptionsCancellable = false
|
||||
|
||||
let loginOptionsViewOnLoginSuccess
|
||||
let loginOptionsViewOnLoginCancel
|
||||
let loginOptionsViewOnCancel
|
||||
let loginOptionsViewCancelHandler
|
||||
|
||||
function loginOptionsCancelEnabled(val){
|
||||
if(val){
|
||||
$(loginOptionsCancelContainer).show()
|
||||
} else {
|
||||
$(loginOptionsCancelContainer).hide()
|
||||
}
|
||||
}
|
||||
|
||||
loginOptionMicrosoft.onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||
ipcRenderer.send(
|
||||
MSFT_OPCODE.OPEN_LOGIN,
|
||||
loginOptionsViewOnLoginSuccess,
|
||||
loginOptionsViewOnLoginCancel
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
loginOptionMojang.onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
||||
loginViewOnSuccess = loginOptionsViewOnLoginSuccess
|
||||
loginViewOnCancel = loginOptionsViewOnLoginCancel
|
||||
loginCancelEnabled(true)
|
||||
})
|
||||
}
|
||||
|
||||
loginOptionsCancelButton.onclick = (e) => {
|
||||
switchView(getCurrentView(), loginOptionsViewOnCancel, 500, 500, () => {
|
||||
// Clear login values (Mojang login)
|
||||
// No cleanup needed for Microsoft.
|
||||
loginUsername.value = ''
|
||||
loginPassword.value = ''
|
||||
if(loginOptionsViewCancelHandler != null){
|
||||
loginOptionsViewCancelHandler()
|
||||
loginOptionsViewCancelHandler = null
|
||||
}
|
||||
})
|
||||
}
|
||||
const loginOptionsCancelContainer = document.getElementById('loginOptionCancelContainer')
|
||||
const loginOptionMicrosoft = document.getElementById('loginOptionMicrosoft')
|
||||
const loginOptionMojang = document.getElementById('loginOptionMojang')
|
||||
const loginOptionsCancelButton = document.getElementById('loginOptionCancelButton')
|
||||
|
||||
let loginOptionsCancellable = true
|
||||
|
||||
let loginOptionsViewOnLoginSuccess
|
||||
let loginOptionsViewOnLoginCancel
|
||||
let loginOptionsViewOnCancel
|
||||
let loginOptionsViewCancelHandler
|
||||
|
||||
function loginOptionsCancelEnabled(val){
|
||||
if(val){
|
||||
$(loginOptionsCancelContainer).show()
|
||||
} else {
|
||||
$(loginOptionsCancelContainer).hide()
|
||||
}
|
||||
}
|
||||
|
||||
loginOptionMicrosoft.onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||
ipcRenderer.send(
|
||||
MSFT_OPCODE.OPEN_LOGIN,
|
||||
loginOptionsViewOnLoginSuccess,
|
||||
loginOptionsViewOnLoginCancel
|
||||
)
|
||||
})
|
||||
}
|
||||
|
||||
loginOptionMojang.onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.login, 500, 500, () => {
|
||||
loginViewOnSuccess = loginOptionsViewOnLoginSuccess
|
||||
loginViewOnCancel = loginOptionsViewOnLoginCancel
|
||||
loginCancelEnabled(true)
|
||||
})
|
||||
}
|
||||
|
||||
loginOptionOffline.onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.loginOffline, 500, 500, () => {
|
||||
loginViewOnSuccess = loginOptionsViewOnLoginSuccess
|
||||
loginViewOnCancel = loginOptionsViewOnLoginCancel
|
||||
loginCancelEnabled(true)
|
||||
})
|
||||
}
|
||||
|
@ -331,6 +331,14 @@ document.getElementById('settingsAddMojangAccount').onclick = (e) => {
|
||||
})
|
||||
}
|
||||
|
||||
document.getElementById('settingsAddOfflineAccount').onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.loginOffline, 500, 500, () => {
|
||||
loginViewOnCancel = VIEWS.settings
|
||||
loginViewOnSuccess = VIEWS.settings
|
||||
loginCancelEnabled(true)
|
||||
})
|
||||
}
|
||||
|
||||
// Bind the add microsoft account button.
|
||||
document.getElementById('settingsAddMicrosoftAccount').onclick = (e) => {
|
||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||
@ -501,6 +509,24 @@ function processLogOut(val, isLastAccount){
|
||||
switchView(getCurrentView(), VIEWS.waiting, 500, 500, () => {
|
||||
ipcRenderer.send(MSFT_OPCODE.OPEN_LOGOUT, uuid, isLastAccount)
|
||||
})
|
||||
} if(targetAcc.type === 'offline') {
|
||||
AuthManager.removeOfflineAccount(uuid).then(() => {
|
||||
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
||||
const selAcc = ConfigManager.getSelectedAccount()
|
||||
refreshAuthAccountSelected(selAcc.uuid)
|
||||
updateSelectedAccount(selAcc)
|
||||
//validateSelectedAccount()
|
||||
}
|
||||
if(isLastAccount) {
|
||||
loginOptionsCancelEnabled(false)
|
||||
loginOptionsViewOnLoginSuccess = VIEWS.settings
|
||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||
switchView(getCurrentView(), VIEWS.loginOptions)
|
||||
}
|
||||
})
|
||||
$(parent).fadeOut(250, () => {
|
||||
parent.remove()
|
||||
})
|
||||
} else {
|
||||
AuthManager.removeMojangAccount(uuid).then(() => {
|
||||
if(!isLastAccount && uuid === prevSelAcc.uuid){
|
||||
@ -603,6 +629,7 @@ function refreshAuthAccountSelected(uuid){
|
||||
|
||||
const settingsCurrentMicrosoftAccounts = document.getElementById('settingsCurrentMicrosoftAccounts')
|
||||
const settingsCurrentMojangAccounts = document.getElementById('settingsCurrentMojangAccounts')
|
||||
const settingsCurrentOfflineAccounts = document.getElementById('settingsCurrentOfflineAccounts')
|
||||
|
||||
/**
|
||||
* Add auth account elements for each one stored in the authentication database.
|
||||
@ -617,6 +644,7 @@ function populateAuthAccounts(){
|
||||
|
||||
let microsoftAuthAccountStr = ''
|
||||
let mojangAuthAccountStr = ''
|
||||
let offlineAuthAccountStr = ''
|
||||
|
||||
authKeys.forEach((val) => {
|
||||
const acc = authAccounts[val]
|
||||
@ -647,6 +675,8 @@ function populateAuthAccounts(){
|
||||
|
||||
if(acc.type === 'microsoft') {
|
||||
microsoftAuthAccountStr += accHtml
|
||||
} if (acc.type === 'offline') {
|
||||
offlineAuthAccountStr += accHtml
|
||||
} else {
|
||||
mojangAuthAccountStr += accHtml
|
||||
}
|
||||
@ -655,6 +685,7 @@ function populateAuthAccounts(){
|
||||
|
||||
settingsCurrentMicrosoftAccounts.innerHTML = microsoftAuthAccountStr
|
||||
settingsCurrentMojangAccounts.innerHTML = mojangAuthAccountStr
|
||||
settingsCurrentOfflineAccounts.innerHTML = offlineAuthAccountStr
|
||||
}
|
||||
|
||||
/**
|
||||
|
@ -1,450 +1,455 @@
|
||||
/**
|
||||
* Initialize UI functions which depend on internal modules.
|
||||
* Loaded after core UI functions are initialized in uicore.js.
|
||||
*/
|
||||
// Requirements
|
||||
const path = require('path')
|
||||
|
||||
const AuthManager = require('./assets/js/authmanager')
|
||||
const ConfigManager = require('./assets/js/configmanager')
|
||||
const DistroManager = require('./assets/js/distromanager')
|
||||
const Lang = require('./assets/js/langloader')
|
||||
|
||||
let rscShouldLoad = false
|
||||
let fatalStartupError = false
|
||||
|
||||
// Mapping of each view to their container IDs.
|
||||
const VIEWS = {
|
||||
landing: '#landingContainer',
|
||||
loginOptions: '#loginOptionsContainer',
|
||||
login: '#loginContainer',
|
||||
settings: '#settingsContainer',
|
||||
welcome: '#welcomeContainer',
|
||||
waiting: '#waitingContainer'
|
||||
}
|
||||
|
||||
// The currently shown view container.
|
||||
let currentView
|
||||
|
||||
/**
|
||||
* Switch launcher views.
|
||||
*
|
||||
* @param {string} current The ID of the current view container.
|
||||
* @param {*} next The ID of the next view container.
|
||||
* @param {*} currentFadeTime Optional. The fade out time for the current view.
|
||||
* @param {*} nextFadeTime Optional. The fade in time for the next view.
|
||||
* @param {*} onCurrentFade Optional. Callback function to execute when the current
|
||||
* view fades out.
|
||||
* @param {*} onNextFade Optional. Callback function to execute when the next view
|
||||
* fades in.
|
||||
*/
|
||||
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
|
||||
currentView = next
|
||||
$(`${current}`).fadeOut(currentFadeTime, () => {
|
||||
onCurrentFade()
|
||||
$(`${next}`).fadeIn(nextFadeTime, () => {
|
||||
onNextFade()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently shown view container.
|
||||
*
|
||||
* @returns {string} The currently shown view container.
|
||||
*/
|
||||
function getCurrentView(){
|
||||
return currentView
|
||||
}
|
||||
|
||||
function showMainUI(data){
|
||||
|
||||
if(!isDev){
|
||||
loggerAutoUpdater.log('Initializing..')
|
||||
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
|
||||
}
|
||||
|
||||
prepareSettings(true)
|
||||
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
||||
refreshServerStatus()
|
||||
setTimeout(() => {
|
||||
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
||||
document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')`
|
||||
$('#main').show()
|
||||
|
||||
const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0
|
||||
|
||||
// If this is enabled in a development environment we'll get ratelimited.
|
||||
// The relaunch frequency is usually far too high.
|
||||
if(!isDev && isLoggedIn){
|
||||
validateSelectedAccount()
|
||||
}
|
||||
|
||||
if(ConfigManager.isFirstLaunch()){
|
||||
currentView = VIEWS.welcome
|
||||
$(VIEWS.welcome).fadeIn(1000)
|
||||
} else {
|
||||
if(isLoggedIn){
|
||||
currentView = VIEWS.landing
|
||||
$(VIEWS.landing).fadeIn(1000)
|
||||
} else {
|
||||
loginOptionsCancelEnabled(false)
|
||||
loginOptionsViewOnLoginSuccess = VIEWS.landing
|
||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||
currentView = VIEWS.loginOptions
|
||||
$(VIEWS.loginOptions).fadeIn(1000)
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
$('#loadingContainer').fadeOut(500, () => {
|
||||
$('#loadSpinnerImage').removeClass('rotating')
|
||||
})
|
||||
}, 250)
|
||||
|
||||
}, 750)
|
||||
// Disable tabbing to the news container.
|
||||
initNews().then(() => {
|
||||
$('#newsContainer *').attr('tabindex', '-1')
|
||||
})
|
||||
}
|
||||
|
||||
function showFatalStartupError(){
|
||||
setTimeout(() => {
|
||||
$('#loadingContainer').fadeOut(250, () => {
|
||||
document.getElementById('overlayContainer').style.background = 'none'
|
||||
setOverlayContent(
|
||||
'Fatal Error: Unable to Load Distribution Index',
|
||||
'A connection could not be established to our servers to download the distribution index. No local copies were available to load. <br><br>The distribution index is an essential file which provides the latest server information. The launcher is unable to start without it. Ensure you are connected to the internet and relaunch the application.',
|
||||
'Close'
|
||||
)
|
||||
setOverlayHandler(() => {
|
||||
const window = remote.getCurrentWindow()
|
||||
window.close()
|
||||
})
|
||||
toggleOverlay(true)
|
||||
})
|
||||
}, 750)
|
||||
}
|
||||
|
||||
/**
|
||||
* Common functions to perform after refreshing the distro index.
|
||||
*
|
||||
* @param {Object} data The distro index object.
|
||||
*/
|
||||
function onDistroRefresh(data){
|
||||
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
||||
refreshServerStatus()
|
||||
initNews()
|
||||
syncModConfigurations(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the mod configurations with the distro index.
|
||||
*
|
||||
* @param {Object} data The distro index object.
|
||||
*/
|
||||
function syncModConfigurations(data){
|
||||
|
||||
const syncedCfgs = []
|
||||
|
||||
for(let serv of data.getServers()){
|
||||
|
||||
const id = serv.getID()
|
||||
const mdls = serv.getModules()
|
||||
const cfg = ConfigManager.getModConfiguration(id)
|
||||
|
||||
if(cfg != null){
|
||||
|
||||
const modsOld = cfg.mods
|
||||
const mods = {}
|
||||
|
||||
for(let mdl of mdls){
|
||||
const type = mdl.getType()
|
||||
|
||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||
if(!mdl.getRequired().isRequired()){
|
||||
const mdlID = mdl.getVersionlessID()
|
||||
if(modsOld[mdlID] == null){
|
||||
mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
} else {
|
||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false)
|
||||
}
|
||||
} else {
|
||||
if(mdl.hasSubModules()){
|
||||
const mdlID = mdl.getVersionlessID()
|
||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
if(typeof v === 'object'){
|
||||
if(modsOld[mdlID] == null){
|
||||
mods[mdlID] = v
|
||||
} else {
|
||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncedCfgs.push({
|
||||
id,
|
||||
mods
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
const mods = {}
|
||||
|
||||
for(let mdl of mdls){
|
||||
const type = mdl.getType()
|
||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||
if(!mdl.getRequired().isRequired()){
|
||||
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
} else {
|
||||
if(mdl.hasSubModules()){
|
||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
if(typeof v === 'object'){
|
||||
mods[mdl.getVersionlessID()] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncedCfgs.push({
|
||||
id,
|
||||
mods
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ConfigManager.setModConfigurations(syncedCfgs)
|
||||
ConfigManager.save()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scan for optional sub modules. If none are found,
|
||||
* this function returns a boolean. If optional sub modules do exist,
|
||||
* a recursive configuration object is returned.
|
||||
*
|
||||
* @returns {boolean | Object} The resolved mod configuration.
|
||||
*/
|
||||
function scanOptionalSubModules(mdls, origin){
|
||||
if(mdls != null){
|
||||
const mods = {}
|
||||
|
||||
for(let mdl of mdls){
|
||||
const type = mdl.getType()
|
||||
// Optional types.
|
||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||
// It is optional.
|
||||
if(!mdl.getRequired().isRequired()){
|
||||
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
} else {
|
||||
if(mdl.hasSubModules()){
|
||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
if(typeof v === 'object'){
|
||||
mods[mdl.getVersionlessID()] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Object.keys(mods).length > 0){
|
||||
const ret = {
|
||||
mods
|
||||
}
|
||||
if(!origin.getRequired().isRequired()){
|
||||
ret.value = origin.getRequired().isDefault()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
return origin.getRequired().isDefault()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively merge an old configuration into a new configuration.
|
||||
*
|
||||
* @param {boolean | Object} o The old configuration value.
|
||||
* @param {boolean | Object} n The new configuration value.
|
||||
* @param {boolean} nReq If the new value is a required mod.
|
||||
*
|
||||
* @returns {boolean | Object} The merged configuration.
|
||||
*/
|
||||
function mergeModConfiguration(o, n, nReq = false){
|
||||
if(typeof o === 'boolean'){
|
||||
if(typeof n === 'boolean') return o
|
||||
else if(typeof n === 'object'){
|
||||
if(!nReq){
|
||||
n.value = o
|
||||
}
|
||||
return n
|
||||
}
|
||||
} else if(typeof o === 'object'){
|
||||
if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true
|
||||
else if(typeof n === 'object'){
|
||||
if(!nReq){
|
||||
n.value = typeof o.value !== 'undefined' ? o.value : true
|
||||
}
|
||||
|
||||
const newMods = Object.keys(n.mods)
|
||||
for(let i=0; i<newMods.length; i++){
|
||||
|
||||
const mod = newMods[i]
|
||||
if(o.mods[mod] != null){
|
||||
n.mods[mod] = mergeModConfiguration(o.mods[mod], n.mods[mod])
|
||||
}
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
||||
// If for some reason we haven't been able to merge,
|
||||
// wipe the old value and use the new one. Just to be safe
|
||||
return n
|
||||
}
|
||||
|
||||
function refreshDistributionIndex(remote, onSuccess, onError){
|
||||
if(remote){
|
||||
DistroManager.pullRemote()
|
||||
.then(onSuccess)
|
||||
.catch(onError)
|
||||
} else {
|
||||
DistroManager.pullLocal()
|
||||
.then(onSuccess)
|
||||
.catch(onError)
|
||||
}
|
||||
}
|
||||
|
||||
async function validateSelectedAccount(){
|
||||
const selectedAcc = ConfigManager.getSelectedAccount()
|
||||
if(selectedAcc != null){
|
||||
const val = await AuthManager.validateSelected()
|
||||
if(!val){
|
||||
ConfigManager.removeAuthAccount(selectedAcc.uuid)
|
||||
ConfigManager.save()
|
||||
const accLen = Object.keys(ConfigManager.getAuthAccounts()).length
|
||||
setOverlayContent(
|
||||
'Failed to Refresh Login',
|
||||
`We were unable to refresh the login for <strong>${selectedAcc.displayName}</strong>. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`,
|
||||
'Login',
|
||||
'Select Another Account'
|
||||
)
|
||||
setOverlayHandler(() => {
|
||||
|
||||
const isMicrosoft = selectedAcc.type === 'microsoft'
|
||||
|
||||
if(isMicrosoft) {
|
||||
// Empty for now
|
||||
} else {
|
||||
// Mojang
|
||||
// For convenience, pre-populate the username of the account.
|
||||
document.getElementById('loginUsername').value = selectedAcc.username
|
||||
validateEmail(selectedAcc.username)
|
||||
}
|
||||
|
||||
loginOptionsViewOnLoginSuccess = getCurrentView()
|
||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||
|
||||
if(accLen > 0) {
|
||||
loginOptionsViewOnCancel = getCurrentView()
|
||||
loginOptionsViewCancelHandler = () => {
|
||||
if(isMicrosoft) {
|
||||
ConfigManager.addMicrosoftAuthAccount(
|
||||
selectedAcc.uuid,
|
||||
selectedAcc.accessToken,
|
||||
selectedAcc.username,
|
||||
selectedAcc.expiresAt,
|
||||
selectedAcc.microsoft.access_token,
|
||||
selectedAcc.microsoft.refresh_token,
|
||||
selectedAcc.microsoft.expires_at
|
||||
)
|
||||
} else {
|
||||
ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
|
||||
}
|
||||
ConfigManager.save()
|
||||
validateSelectedAccount()
|
||||
}
|
||||
loginOptionsCancelEnabled(true)
|
||||
} else {
|
||||
loginOptionsCancelEnabled(false)
|
||||
}
|
||||
toggleOverlay(false)
|
||||
switchView(getCurrentView(), VIEWS.loginOptions)
|
||||
})
|
||||
setDismissHandler(() => {
|
||||
if(accLen > 1){
|
||||
prepareAccountSelectionList()
|
||||
$('#overlayContent').fadeOut(250, () => {
|
||||
bindOverlayKeys(true, 'accountSelectContent', true)
|
||||
$('#accountSelectContent').fadeIn(250)
|
||||
})
|
||||
} else {
|
||||
const accountsObj = ConfigManager.getAuthAccounts()
|
||||
const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v])
|
||||
// This function validates the account switch.
|
||||
setSelectedAccount(accounts[0].uuid)
|
||||
toggleOverlay(false)
|
||||
}
|
||||
})
|
||||
toggleOverlay(true, accLen > 0)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary function to update the selected account along
|
||||
* with the relevent UI elements.
|
||||
*
|
||||
* @param {string} uuid The UUID of the account.
|
||||
*/
|
||||
function setSelectedAccount(uuid){
|
||||
const authAcc = ConfigManager.setSelectedAccount(uuid)
|
||||
ConfigManager.save()
|
||||
updateSelectedAccount(authAcc)
|
||||
validateSelectedAccount()
|
||||
}
|
||||
|
||||
// Synchronous Listener
|
||||
document.addEventListener('readystatechange', function(){
|
||||
|
||||
if (document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||
if(rscShouldLoad){
|
||||
rscShouldLoad = false
|
||||
if(!fatalStartupError){
|
||||
const data = DistroManager.getDistribution()
|
||||
showMainUI(data)
|
||||
} else {
|
||||
showFatalStartupError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, false)
|
||||
|
||||
// Actions that must be performed after the distribution index is downloaded.
|
||||
ipcRenderer.on('distributionIndexDone', (event, res) => {
|
||||
if(res) {
|
||||
const data = DistroManager.getDistribution()
|
||||
syncModConfigurations(data)
|
||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||
showMainUI(data)
|
||||
} else {
|
||||
rscShouldLoad = true
|
||||
}
|
||||
} else {
|
||||
fatalStartupError = true
|
||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||
showFatalStartupError()
|
||||
} else {
|
||||
rscShouldLoad = true
|
||||
}
|
||||
}
|
||||
})
|
||||
/**
|
||||
* Initialize UI functions which depend on internal modules.
|
||||
* Loaded after core UI functions are initialized in uicore.js.
|
||||
*/
|
||||
// Requirements
|
||||
const path = require('path')
|
||||
|
||||
const AuthManager = require('./assets/js/authmanager')
|
||||
const ConfigManager = require('./assets/js/configmanager')
|
||||
const DistroManager = require('./assets/js/distromanager')
|
||||
const Lang = require('./assets/js/langloader')
|
||||
|
||||
let rscShouldLoad = false
|
||||
let fatalStartupError = false
|
||||
|
||||
// Mapping of each view to their container IDs.
|
||||
const VIEWS = {
|
||||
landing: '#landingContainer',
|
||||
loginOptions: '#loginOptionsContainer',
|
||||
login: '#loginContainer',
|
||||
loginOffline: '#loginOfflineContainer',
|
||||
settings: '#settingsContainer',
|
||||
welcome: '#welcomeContainer',
|
||||
waiting: '#waitingContainer',
|
||||
dynmap: '#dynmapContainer'
|
||||
}
|
||||
|
||||
// The currently shown view container.
|
||||
let currentView
|
||||
|
||||
/**
|
||||
* Switch launcher views.
|
||||
*
|
||||
* @param {string} current The ID of the current view container.
|
||||
* @param {*} next The ID of the next view container.
|
||||
* @param {*} currentFadeTime Optional. The fade out time for the current view.
|
||||
* @param {*} nextFadeTime Optional. The fade in time for the next view.
|
||||
* @param {*} onCurrentFade Optional. Callback function to execute when the current
|
||||
* view fades out.
|
||||
* @param {*} onNextFade Optional. Callback function to execute when the next view
|
||||
* fades in.
|
||||
*/
|
||||
function switchView(current, next, currentFadeTime = 500, nextFadeTime = 500, onCurrentFade = () => {}, onNextFade = () => {}){
|
||||
currentView = next
|
||||
$(`${current}`).fadeOut(currentFadeTime, () => {
|
||||
onCurrentFade()
|
||||
$(`${next}`).fadeIn(nextFadeTime, () => {
|
||||
onNextFade()
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the currently shown view container.
|
||||
*
|
||||
* @returns {string} The currently shown view container.
|
||||
*/
|
||||
function getCurrentView(){
|
||||
return currentView
|
||||
}
|
||||
|
||||
function showMainUI(data){
|
||||
|
||||
if(!isDev){
|
||||
loggerAutoUpdater.log('Initializing..')
|
||||
ipcRenderer.send('autoUpdateAction', 'initAutoUpdater', ConfigManager.getAllowPrerelease())
|
||||
}
|
||||
|
||||
prepareSettings(true)
|
||||
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
||||
refreshServerStatus()
|
||||
setTimeout(() => {
|
||||
document.getElementById('frameBar').style.backgroundColor = 'rgba(0, 0, 0, 0.5)'
|
||||
document.body.style.backgroundImage = `url('assets/images/backgrounds/${document.body.getAttribute('bkid')}.jpg')`
|
||||
$('#main').show()
|
||||
|
||||
const isLoggedIn = Object.keys(ConfigManager.getAuthAccounts()).length > 0
|
||||
|
||||
// If this is enabled in a development environment we'll get ratelimited.
|
||||
// The relaunch frequency is usually far too high.
|
||||
//if(!isDev && isLoggedIn){
|
||||
if(isLoggedIn){
|
||||
validateSelectedAccount()
|
||||
}
|
||||
|
||||
if(ConfigManager.isFirstLaunch()){
|
||||
currentView = VIEWS.welcome
|
||||
$(VIEWS.welcome).fadeIn(1000)
|
||||
} else {
|
||||
if(isLoggedIn){
|
||||
currentView = VIEWS.landing
|
||||
$(VIEWS.landing).fadeIn(1000)
|
||||
} else {
|
||||
loginOptionsCancelEnabled(false)
|
||||
loginOptionsViewOnLoginSuccess = VIEWS.landing
|
||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||
currentView = VIEWS.loginOptions
|
||||
$(VIEWS.loginOptions).fadeIn(1000)
|
||||
}
|
||||
}
|
||||
|
||||
setTimeout(() => {
|
||||
$('#loadingContainer').fadeOut(500, () => {
|
||||
$('#loadSpinnerImage').removeClass('rotating')
|
||||
})
|
||||
}, 250)
|
||||
|
||||
}, 750)
|
||||
// Disable tabbing to the news container.
|
||||
initNews().then(() => {
|
||||
$('#newsContainer *').attr('tabindex', '-1')
|
||||
})
|
||||
}
|
||||
|
||||
function showFatalStartupError(){
|
||||
setTimeout(() => {
|
||||
$('#loadingContainer').fadeOut(250, () => {
|
||||
document.getElementById('overlayContainer').style.background = 'none'
|
||||
setOverlayContent(
|
||||
'Fatal Error: Unable to Load Distribution Index',
|
||||
'A connection could not be established to our servers to download the distribution index. No local copies were available to load. <br><br>The distribution index is an essential file which provides the latest server information. The launcher is unable to start without it. Ensure you are connected to the internet and relaunch the application.',
|
||||
'Close'
|
||||
)
|
||||
setOverlayHandler(() => {
|
||||
const window = remote.getCurrentWindow()
|
||||
window.close()
|
||||
})
|
||||
toggleOverlay(true)
|
||||
})
|
||||
}, 750)
|
||||
}
|
||||
|
||||
/**
|
||||
* Common functions to perform after refreshing the distro index.
|
||||
*
|
||||
* @param {Object} data The distro index object.
|
||||
*/
|
||||
function onDistroRefresh(data){
|
||||
updateSelectedServer(data.getServer(ConfigManager.getSelectedServer()))
|
||||
refreshServerStatus()
|
||||
initNews()
|
||||
syncModConfigurations(data)
|
||||
}
|
||||
|
||||
/**
|
||||
* Sync the mod configurations with the distro index.
|
||||
*
|
||||
* @param {Object} data The distro index object.
|
||||
*/
|
||||
function syncModConfigurations(data){
|
||||
|
||||
const syncedCfgs = []
|
||||
|
||||
for(let serv of data.getServers()){
|
||||
|
||||
const id = serv.getID()
|
||||
const mdls = serv.getModules()
|
||||
const cfg = ConfigManager.getModConfiguration(id)
|
||||
|
||||
if(cfg != null){
|
||||
|
||||
const modsOld = cfg.mods
|
||||
const mods = {}
|
||||
|
||||
for(let mdl of mdls){
|
||||
const type = mdl.getType()
|
||||
|
||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||
if(!mdl.getRequired().isRequired()){
|
||||
const mdlID = mdl.getVersionlessID()
|
||||
if(modsOld[mdlID] == null){
|
||||
mods[mdlID] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
} else {
|
||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], scanOptionalSubModules(mdl.getSubModules(), mdl), false)
|
||||
}
|
||||
} else {
|
||||
if(mdl.hasSubModules()){
|
||||
const mdlID = mdl.getVersionlessID()
|
||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
if(typeof v === 'object'){
|
||||
if(modsOld[mdlID] == null){
|
||||
mods[mdlID] = v
|
||||
} else {
|
||||
mods[mdlID] = mergeModConfiguration(modsOld[mdlID], v, true)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncedCfgs.push({
|
||||
id,
|
||||
mods
|
||||
})
|
||||
|
||||
} else {
|
||||
|
||||
const mods = {}
|
||||
|
||||
for(let mdl of mdls){
|
||||
const type = mdl.getType()
|
||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||
if(!mdl.getRequired().isRequired()){
|
||||
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
} else {
|
||||
if(mdl.hasSubModules()){
|
||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
if(typeof v === 'object'){
|
||||
mods[mdl.getVersionlessID()] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
syncedCfgs.push({
|
||||
id,
|
||||
mods
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
ConfigManager.setModConfigurations(syncedCfgs)
|
||||
ConfigManager.save()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively scan for optional sub modules. If none are found,
|
||||
* this function returns a boolean. If optional sub modules do exist,
|
||||
* a recursive configuration object is returned.
|
||||
*
|
||||
* @returns {boolean | Object} The resolved mod configuration.
|
||||
*/
|
||||
function scanOptionalSubModules(mdls, origin){
|
||||
if(mdls != null){
|
||||
const mods = {}
|
||||
|
||||
for(let mdl of mdls){
|
||||
const type = mdl.getType()
|
||||
// Optional types.
|
||||
if(type === DistroManager.Types.ForgeMod || type === DistroManager.Types.LiteMod || type === DistroManager.Types.LiteLoader){
|
||||
// It is optional.
|
||||
if(!mdl.getRequired().isRequired()){
|
||||
mods[mdl.getVersionlessID()] = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
} else {
|
||||
if(mdl.hasSubModules()){
|
||||
const v = scanOptionalSubModules(mdl.getSubModules(), mdl)
|
||||
if(typeof v === 'object'){
|
||||
mods[mdl.getVersionlessID()] = v
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(Object.keys(mods).length > 0){
|
||||
const ret = {
|
||||
mods
|
||||
}
|
||||
if(!origin.getRequired().isRequired()){
|
||||
ret.value = origin.getRequired().isDefault()
|
||||
}
|
||||
return ret
|
||||
}
|
||||
}
|
||||
return origin.getRequired().isDefault()
|
||||
}
|
||||
|
||||
/**
|
||||
* Recursively merge an old configuration into a new configuration.
|
||||
*
|
||||
* @param {boolean | Object} o The old configuration value.
|
||||
* @param {boolean | Object} n The new configuration value.
|
||||
* @param {boolean} nReq If the new value is a required mod.
|
||||
*
|
||||
* @returns {boolean | Object} The merged configuration.
|
||||
*/
|
||||
function mergeModConfiguration(o, n, nReq = false){
|
||||
if(typeof o === 'boolean'){
|
||||
if(typeof n === 'boolean') return o
|
||||
else if(typeof n === 'object'){
|
||||
if(!nReq){
|
||||
n.value = o
|
||||
}
|
||||
return n
|
||||
}
|
||||
} else if(typeof o === 'object'){
|
||||
if(typeof n === 'boolean') return typeof o.value !== 'undefined' ? o.value : true
|
||||
else if(typeof n === 'object'){
|
||||
if(!nReq){
|
||||
n.value = typeof o.value !== 'undefined' ? o.value : true
|
||||
}
|
||||
|
||||
const newMods = Object.keys(n.mods)
|
||||
for(let i=0; i<newMods.length; i++){
|
||||
|
||||
const mod = newMods[i]
|
||||
if(o.mods[mod] != null){
|
||||
n.mods[mod] = mergeModConfiguration(o.mods[mod], n.mods[mod])
|
||||
}
|
||||
}
|
||||
|
||||
return n
|
||||
}
|
||||
}
|
||||
// If for some reason we haven't been able to merge,
|
||||
// wipe the old value and use the new one. Just to be safe
|
||||
return n
|
||||
}
|
||||
|
||||
function refreshDistributionIndex(remote, onSuccess, onError){
|
||||
if(remote){
|
||||
DistroManager.pullRemote()
|
||||
.then(onSuccess)
|
||||
.catch(onError)
|
||||
} else {
|
||||
DistroManager.pullLocal()
|
||||
.then(onSuccess)
|
||||
.catch(onError)
|
||||
}
|
||||
}
|
||||
|
||||
async function validateSelectedAccount(){
|
||||
const selectedAcc = ConfigManager.getSelectedAccount()
|
||||
if(selectedAcc != null && selectedAcc.type != 'offline'){
|
||||
const val = await AuthManager.validateSelected()
|
||||
if(!val){
|
||||
ConfigManager.removeAuthAccount(selectedAcc.uuid)
|
||||
ConfigManager.save()
|
||||
const accLen = Object.keys(ConfigManager.getAuthAccounts()).length
|
||||
setOverlayContent(
|
||||
'Failed to Refresh Login',
|
||||
`We were unable to refresh the login for <strong>${selectedAcc.displayName}</strong>. Please ${accLen > 0 ? 'select another account or ' : ''} login again.`,
|
||||
'Login',
|
||||
'Select Another Account'
|
||||
)
|
||||
setOverlayHandler(() => {
|
||||
|
||||
const isMicrosoft = selectedAcc.type === 'microsoft'
|
||||
|
||||
if(isMicrosoft) {
|
||||
// Empty for now
|
||||
} else {
|
||||
// Mojang
|
||||
// For convenience, pre-populate the username of the account.
|
||||
document.getElementById('loginUsername').value = selectedAcc.username
|
||||
validateEmail(selectedAcc.username)
|
||||
}
|
||||
|
||||
loginOptionsViewOnLoginSuccess = getCurrentView()
|
||||
loginOptionsViewOnLoginCancel = VIEWS.loginOptions
|
||||
|
||||
if(accLen > 0) {
|
||||
loginOptionsViewOnCancel = getCurrentView()
|
||||
loginOptionsViewCancelHandler = () => {
|
||||
if(isMicrosoft) {
|
||||
ConfigManager.addMicrosoftAuthAccount(
|
||||
selectedAcc.uuid,
|
||||
selectedAcc.accessToken,
|
||||
selectedAcc.username,
|
||||
selectedAcc.expiresAt,
|
||||
selectedAcc.microsoft.access_token,
|
||||
selectedAcc.microsoft.refresh_token,
|
||||
selectedAcc.microsoft.expires_at
|
||||
)
|
||||
} else {
|
||||
ConfigManager.addMojangAuthAccount(selectedAcc.uuid, selectedAcc.accessToken, selectedAcc.username, selectedAcc.displayName)
|
||||
}
|
||||
ConfigManager.save()
|
||||
validateSelectedAccount()
|
||||
}
|
||||
loginOptionsCancelEnabled(true)
|
||||
} else {
|
||||
loginOptionsCancelEnabled(false)
|
||||
}
|
||||
toggleOverlay(false)
|
||||
switchView(getCurrentView(), VIEWS.loginOptions)
|
||||
})
|
||||
setDismissHandler(() => {
|
||||
if(accLen > 1){
|
||||
prepareAccountSelectionList()
|
||||
$('#overlayContent').fadeOut(250, () => {
|
||||
bindOverlayKeys(true, 'accountSelectContent', true)
|
||||
$('#accountSelectContent').fadeIn(250)
|
||||
})
|
||||
} else {
|
||||
const accountsObj = ConfigManager.getAuthAccounts()
|
||||
const accounts = Array.from(Object.keys(accountsObj), v => accountsObj[v])
|
||||
// This function validates the account switch.
|
||||
setSelectedAccount(accounts[0].uuid)
|
||||
toggleOverlay(false)
|
||||
}
|
||||
})
|
||||
toggleOverlay(true, accLen > 0)
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
} else {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Temporary function to update the selected account along
|
||||
* with the relevent UI elements.
|
||||
*
|
||||
* @param {string} uuid The UUID of the account.
|
||||
*/
|
||||
function setSelectedAccount(uuid){
|
||||
const authAcc = ConfigManager.setSelectedAccount(uuid)
|
||||
ConfigManager.save()
|
||||
updateSelectedAccount(authAcc)
|
||||
if (ConfigManager.getAuthAccounts[uuid].type !== 'offline'){
|
||||
validateSelectedAccount()
|
||||
}
|
||||
}
|
||||
|
||||
// Synchronous Listener
|
||||
document.addEventListener('readystatechange', function(){
|
||||
|
||||
if (document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||
if(rscShouldLoad){
|
||||
rscShouldLoad = false
|
||||
if(!fatalStartupError){
|
||||
const data = DistroManager.getDistribution()
|
||||
showMainUI(data)
|
||||
} else {
|
||||
showFatalStartupError()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}, false)
|
||||
|
||||
// Actions that must be performed after the distribution index is downloaded.
|
||||
ipcRenderer.on('distributionIndexDone', (event, res) => {
|
||||
if(res) {
|
||||
const data = DistroManager.getDistribution()
|
||||
syncModConfigurations(data)
|
||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||
showMainUI(data)
|
||||
} else {
|
||||
rscShouldLoad = true
|
||||
}
|
||||
} else {
|
||||
fatalStartupError = true
|
||||
if(document.readyState === 'interactive' || document.readyState === 'complete'){
|
||||
showFatalStartupError()
|
||||
} else {
|
||||
rscShouldLoad = true
|
||||
}
|
||||
}
|
||||
})
|
||||
|
22
app/dynmap.ejs
Normal file
22
app/dynmap.ejs
Normal file
@ -0,0 +1,22 @@
|
||||
<div id="dynmapContainer" style="display: none;">
|
||||
<div class="FloatingButtonContainer" id="center">
|
||||
<div class="bot_wrapper">
|
||||
<div id="content">
|
||||
<button id="dynmapDoneButton"> <!-- Rename all elements to dynmapEtc -->
|
||||
<div id="newsButtonAlert" style="display: none;"></div>
|
||||
<svg id="newsButtonSVG" viewBox="0 0 24.87 13.97">
|
||||
<defs>
|
||||
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;}</style>
|
||||
</defs>
|
||||
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
|
||||
</svg>
|
||||
<span id="dynmapDoneButtonText">MAP</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="iframecontainer">
|
||||
<iframe id="dynmapiframe" src="https://minemap.gregbrzezinski.com" frameborder="0"></iframe>
|
||||
</div>
|
||||
<script src="./assets/js/scripts/dynmap.js"></script>
|
||||
</div>
|
@ -26,15 +26,24 @@
|
||||
<div id="settingsTooltip">Settings</div>
|
||||
</button>
|
||||
</div>
|
||||
<!-- map integration button
|
||||
<div class="mediaContainer" id="mapMediaContainer">
|
||||
<button class="mediaButton" id="mapMediaButton">
|
||||
<svg id="settingsSVG" class="mediaSVG" viewBox="0 0 141.36 137.43">
|
||||
<path d="M70.70475616319865,83.36934004916053 a15.320781354859122,15.320781354859122 0 1 1 14.454501310561755,-15.296030496450625 A14.850515045097694,14.850515045097694 0 0 1 70.70475616319865,83.36934004916053 M123.25082856443602,55.425620905968366 h-12.375429204248078 A45.54157947163293,45.54157947163293 0 0 0 107.21227231573047,46.243052436416285 l8.613298726156664,-9.108315894326587 a9.727087354538993,9.727087354538993 0 0 0 0,-13.167456673319956 l-3.465120177189462,-3.6631270444574313 a8.489544434114185,8.489544434114185 0 0 0 -12.375429204248078,0 l-8.613298726156664,9.108315894326587 A40.442902639482725,40.442902639482725 0 0 0 81.99114759747292,25.427580514871032 V12.532383284044531 a9.108315894326587,9.108315894326587 0 0 0 -8.811305593424633,-9.306322761594556 h-4.950171681699231 a9.108315894326587,9.108315894326587 0 0 0 -8.811305593424633,9.306322761594556 v12.895197230826497 a40.17064319698927,40.17064319698927 0 0 0 -9.331073620003052,4.0591407789933704 l-8.613298726156664,-9.108315894326587 a8.489544434114185,8.489544434114185 0 0 0 -12.375429204248078,0 L25.58394128451018,23.967279868769744 a9.727087354538993,9.727087354538993 0 0 0 0,13.167456673319956 L34.19724001066683,46.243052436416285 a45.07131316187151,45.07131316187151 0 0 0 -3.6631270444574313,9.083565035918088 h-12.375429204248078 a9.083565035918088,9.083565035918088 0 0 0 -8.811305593424633,9.306322761594556 v5.197680265784193 a9.108315894326587,9.108315894326587 0 0 0 8.811305593424633,9.306322761594556 h11.979415469712139 a45.69008462208391,45.69008462208391 0 0 0 4.0591407789933704,10.642869115653347 l-8.613298726156664,9.108315894326587 a9.727087354538993,9.727087354538993 0 0 0 0,13.167456673319956 l3.465120177189462,3.6631270444574313 a8.489544434114185,8.489544434114185 0 0 0 12.375429204248078,0 l8.613298726156664,-9.108315894326587 a40.49240435629971,40.49240435629971 0 0 0 9.331073620003052,4.0591407789933704 v12.895197230826497 a9.083565035918088,9.083565035918088 0 0 0 8.811305593424633,9.306322761594556 h4.950171681699231 A9.083565035918088,9.083565035918088 0 0 0 81.99114759747292,123.68848839660077 V110.79329116577425 a40.78941465720167,40.78941465720167 0 0 0 9.331073620003052,-4.0591407789933704 l8.613298726156664,9.108315894326587 a8.489544434114185,8.489544434114185 0 0 0 12.375429204248078,0 l3.465120177189462,-3.6631270444574313 a9.727087354538993,9.727087354538993 0 0 0 0,-13.167456673319956 l-8.613298726156664,-9.108315894326587 a45.665333763675406,45.665333763675406 0 0 0 4.034389920584874,-10.642869115653347 h12.004166328120636 a9.108315894326587,9.108315894326587 0 0 0 8.811305593424633,-9.306322761594556 v-5.197680265784193 a9.083565035918088,9.083565035918088 0 0 0 -8.811305593424633,-9.306322761594556 " id="svg_3" class=""/>
|
||||
</svg>
|
||||
<div id="settingsTooltip">Map</div>
|
||||
</button>
|
||||
</div>
|
||||
-->
|
||||
</div>
|
||||
<div class="mediaDivider"></div>
|
||||
<div id="externalMedia">
|
||||
<div class="mediaContainer">
|
||||
<a href="https://github.com/dscalzi/HeliosLauncher" class="mediaURL" id="linkURL">
|
||||
<svg id="linkSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
||||
<a href="https://discord.gg/JwKaVJG" class="mediaURL" id="discordURL">
|
||||
<svg id="discordSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
||||
<g>
|
||||
<path d="M75.37,65.51a3.85,3.85,0,0,0-1.73.42,8.22,8.22,0,0,1,.94,3.76A8.36,8.36,0,0,1,66.23,78H46.37a8.35,8.35,0,1,1,0-16.7h9.18a21.51,21.51,0,0,1,6.65-8.72H46.37a17.07,17.07,0,1,0,0,34.15H66.23A17,17,0,0,0,82.77,65.51Z"/>
|
||||
<path d="M66,73.88a3.85,3.85,0,0,0,1.73-.42,8.22,8.22,0,0,1-.94-3.76,8.36,8.36,0,0,1,8.35-8.35H95A8.35,8.35,0,1,1,95,78H85.8a21.51,21.51,0,0,1-6.65,8.72H95a17.07,17.07,0,0,0,0-34.15H75.13A17,17,0,0,0,58.59,73.88Z"/>
|
||||
<path d="M81.23,78.48a6.14,6.14,0,1,1,6.14-6.14,6.14,6.14,0,0,1-6.14,6.14M60,78.48a6.14,6.14,0,1,1,6.14-6.14A6.14,6.14,0,0,1,60,78.48M104.41,73c-.92-7.7-8.24-22.9-8.24-22.9A43,43,0,0,0,88,45.59a17.88,17.88,0,0,0-8.38-1.27l-.13,1.06a23.52,23.52,0,0,1,5.8,1.95,87.59,87.59,0,0,1,8.17,4.87s-10.32-5.63-22.27-5.63a51.32,51.32,0,0,0-23.2,5.63,87.84,87.84,0,0,1,8.17-4.87,23.57,23.57,0,0,1,5.8-1.95l-.13-1.06a17.88,17.88,0,0,0-8.38,1.27,42.84,42.84,0,0,0-8.21,4.56S37.87,65.35,37,73s-.37,11.54-.37,11.54,4.22,5.68,9.9,7.14,7.7,1.47,7.7,1.47l3.75-4.68a21.22,21.22,0,0,1-4.65-2A24.47,24.47,0,0,1,47.93,82S61.16,88.4,70.68,88.4c10,0,22.75-6.44,22.75-6.44a24.56,24.56,0,0,1-5.35,4.56,21.22,21.22,0,0,1-4.65,2l3.75,4.68s2,0,7.7-1.47,9.89-7.14,9.89-7.14.55-3.85-.37-11.54"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
@ -49,39 +58,11 @@
|
||||
</a>
|
||||
</div>
|
||||
<div class="mediaContainer">
|
||||
<a href="#" class="mediaURL" id="instagramURL" disabled>
|
||||
<svg id="instagramSVG" class="mediaSVG" viewBox="0 0 5040 5040">
|
||||
<defs>
|
||||
<radialGradient id="instaFill" cx="30%" cy="107%" r="150%">
|
||||
<stop offset="0%" stop-color="#fdf497"/>
|
||||
<stop offset="5%" stop-color="#fdf497"/>
|
||||
<stop offset="45%" stop-color="#fd5949"/>
|
||||
<stop offset="60%" stop-color="#d6249f"/>
|
||||
<stop offset="90%" stop-color="#285AEB"/>
|
||||
</radialGradient>
|
||||
</defs>
|
||||
<a href="https://github.com/dscalzi/HeliosLauncher" class="mediaURL" id="linkURL">
|
||||
<svg id="linkSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
||||
<g>
|
||||
<path d="M1390 5024 c-163 -9 -239 -19 -315 -38 -281 -70 -477 -177 -660 -361 -184 -184 -292 -380 -361 -660 -43 -171 -53 -456 -53 -1445 0 -989 10 -1274 53 -1445 69 -280 177 -476 361 -660 184 -184 380 -292 660 -361 171 -43 456 -53 1445 -53 989 0 1274 10 1445 53 280 69 476 177 660 361 184 184 292 380 361 660 43 171 53 456 53 1445 0 989 -10 1274 -53 1445 -69 280 -177 476 -361 660 -184 184 -380 292 -660 361 -174 44 -454 53 -1470 52 -599 0 -960 -5 -1105 -14z m2230 -473 c58 -6 141 -18 185 -27 397 -78 638 -318 719 -714 37 -183 41 -309 41 -1290 0 -981 -4 -1107 -41 -1290 -81 -395 -319 -633 -714 -714 -183 -37 -309 -41 -1290 -41 -981 0 -1107 4 -1290 41 -397 81 -636 322 -714 719 -33 166 -38 296 -43 1100 -5 796 3 1203 27 1380 67 489 338 758 830 825 47 7 162 15 255 20 250 12 1907 4 2035 -9z"/>
|
||||
<path d="M2355 3819 c-307 -42 -561 -172 -780 -400 -244 -253 -359 -543 -359 -899 0 -361 116 -648 367 -907 262 -269 563 -397 937 -397 374 0 675 128 937 397 251 259 367 546 367 907 0 361 -116 648 -367 907 -197 203 -422 326 -690 378 -101 20 -317 27 -412 14z m400 -509 c275 -88 470 -284 557 -560 20 -65 23 -95 23 -230 0 -135 -3 -165 -23 -230 -88 -278 -284 -474 -562 -562 -65 -20 -95 -23 -230 -23 -135 0 -165 3 -230 23 -278 88 -474 284 -562 562 -20 65 -23 95 -23 230 0 135 3 165 23 230 73 230 219 403 427 507 134 67 212 83 390 79 111 -3 155 -8 210 -26z"/>
|
||||
<path d="M3750 1473 c-29 -11 -66 -38 -106 -77 -70 -71 -94 -126 -94 -221 0 -95 24 -150 94 -221 72 -71 126 -94 225 -94 168 0 311 143 311 311 0 99 -23 154 -94 225 -43 42 -76 66 -110 77 -61 21 -166 21 -226 0z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mediaContainer">
|
||||
<a href="#" class="mediaURL" id="youtubeURL" disabled>
|
||||
<svg id="youtubeSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
||||
<g>
|
||||
<path d="M84.8,69.52,65.88,79.76V59.27Zm23.65.59c0-5.14-.79-17.63-3.94-20.57S99,45.86,73.37,45.86s-28,.73-31.14,3.68S38.29,65,38.29,70.11s.79,17.63,3.94,20.57,5.52,3.68,31.14,3.68,28-.74,31.14-3.68,3.94-15.42,3.94-20.57"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
</div>
|
||||
<div class="mediaContainer">
|
||||
<a href="https://discord.gg/zNWUXdt" class="mediaURL" id="discordURL">
|
||||
<svg id="discordSVG" class="mediaSVG" viewBox="35.34 34.3575 70.68 68.71500">
|
||||
<g>
|
||||
<path d="M81.23,78.48a6.14,6.14,0,1,1,6.14-6.14,6.14,6.14,0,0,1-6.14,6.14M60,78.48a6.14,6.14,0,1,1,6.14-6.14A6.14,6.14,0,0,1,60,78.48M104.41,73c-.92-7.7-8.24-22.9-8.24-22.9A43,43,0,0,0,88,45.59a17.88,17.88,0,0,0-8.38-1.27l-.13,1.06a23.52,23.52,0,0,1,5.8,1.95,87.59,87.59,0,0,1,8.17,4.87s-10.32-5.63-22.27-5.63a51.32,51.32,0,0,0-23.2,5.63,87.84,87.84,0,0,1,8.17-4.87,23.57,23.57,0,0,1,5.8-1.95l-.13-1.06a17.88,17.88,0,0,0-8.38,1.27,42.84,42.84,0,0,0-8.21,4.56S37.87,65.35,37,73s-.37,11.54-.37,11.54,4.22,5.68,9.9,7.14,7.7,1.47,7.7,1.47l3.75-4.68a21.22,21.22,0,0,1-4.65-2A24.47,24.47,0,0,1,47.93,82S61.16,88.4,70.68,88.4c10,0,22.75-6.44,22.75-6.44a24.56,24.56,0,0,1-5.35,4.56,21.22,21.22,0,0,1-4.65,2l3.75,4.68s2,0,7.7-1.47,9.89-7.14,9.89-7.14.55-3.85-.37-11.54"/>
|
||||
<path d="M75.37,65.51a3.85,3.85,0,0,0-1.73.42,8.22,8.22,0,0,1,.94,3.76A8.36,8.36,0,0,1,66.23,78H46.37a8.35,8.35,0,1,1,0-16.7h9.18a21.51,21.51,0,0,1,6.65-8.72H46.37a17.07,17.07,0,1,0,0,34.15H66.23A17,17,0,0,0,82.77,65.51Z"/>
|
||||
<path d="M66,73.88a3.85,3.85,0,0,0,1.73-.42,8.22,8.22,0,0,1-.94-3.76,8.36,8.36,0,0,1,8.35-8.35H95A8.35,8.35,0,1,1,95,78H85.8a21.51,21.51,0,0,1-6.65,8.72H95a17.07,17.07,0,0,0,0-34.15H75.13A17,17,0,0,0,58.59,73.88Z"/>
|
||||
</g>
|
||||
</svg>
|
||||
</a>
|
||||
@ -125,18 +106,13 @@
|
||||
<div class="bot_wrapper">
|
||||
<div id="content">
|
||||
<button id="newsButton">
|
||||
<!--<img src="assets/images/icons/arrow.svg" id="newsButtonSVG"/>-->
|
||||
|
||||
<div id="newsButtonAlert" style="display: none;"></div>
|
||||
<svg id="newsButtonSVG" viewBox="0 0 24.87 13.97">
|
||||
<defs>
|
||||
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;}</style>
|
||||
</defs>
|
||||
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
|
||||
</svg>
|
||||
<span id="newsButtonText">NEWS</span>
|
||||
<svg xmlns="http://www.w3.org/2000/svg" id="mapsvg" viewBox="0 0 24 24" width="20" height="20"><path d="M12,0A12,12,0,1,0,24,12,12.013,12.013,0,0,0,12,0ZM22,12a9.938,9.938,0,0,1-1.662,5.508l-1.192-1.193A.5.5,0,0,1,19,15.962V15a3,3,0,0,0-3-3H13a1,1,0,0,1-1-1v-.5a.5.5,0,0,1,.5-.5A2.5,2.5,0,0,0,15,7.5v-1a.5.5,0,0,1,.5-.5h1.379a2.516,2.516,0,0,0,1.767-.732l.377-.377A9.969,9.969,0,0,1,22,12Zm-19.951.963,3.158,3.158A2.978,2.978,0,0,0,7.329,17H10a1,1,0,0,1,1,1v3.949A10.016,10.016,0,0,1,2.049,12.963ZM13,21.949V18a3,3,0,0,0-3-3H7.329a1,1,0,0,1-.708-.293L2.163,10.249A9.978,9.978,0,0,1,17.456,3.63l-.224.224A.507.507,0,0,1,16.879,4H15.5A2.5,2.5,0,0,0,13,6.5v1a.5.5,0,0,1-.5.5A2.5,2.5,0,0,0,10,10.5V11a3,3,0,0,0,3,3h3a1,1,0,0,1,1,1v.962a2.516,2.516,0,0,0,.732,1.767l1.337,1.337A9.971,9.971,0,0,1,13,21.949Z"/></svg>
|
||||
<span id="newsButtonText">MAP</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="right">
|
||||
<div class="bot_wrapper">
|
||||
@ -159,7 +135,10 @@
|
||||
</div>
|
||||
</div>
|
||||
<div id="newsContainer">
|
||||
<div id="newsContent" article="-1" style="display: none;">
|
||||
<div id="iframecontainer">
|
||||
<iframe id="dynmapiframe" src="https://minemap.gregbrzezinski.com" frameborder="0"></iframe>
|
||||
</div>
|
||||
<!-- <div id="newsContent" article="-1" style="display: none;">
|
||||
<div id="newsStatusContainer">
|
||||
<div id="newsStatusContent">
|
||||
<div id="newsTitleContainer">
|
||||
@ -198,7 +177,7 @@
|
||||
<div id="newsArticleContainer">
|
||||
<div id="newsArticleContent">
|
||||
<div id="newsArticleContentScrollable">
|
||||
<!-- Article Content -->
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@ -214,7 +193,7 @@
|
||||
<div id="newsErrorNone" style="display: none;">
|
||||
<span id="nENoneSpan" class="newsErrorContent">No News</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>-->
|
||||
</div>
|
||||
<script src="./assets/js/scripts/landing.js"></script>
|
||||
</div>
|
31
app/loginOffline.ejs
Normal file
31
app/loginOffline.ejs
Normal file
@ -0,0 +1,31 @@
|
||||
<div id="loginOfflineContainer" style="display: none;">
|
||||
<div id="loginOfflineCancelContainer" > <!--Delete style="" as temp fix-->
|
||||
<button id="loginOfflineCancelButton">
|
||||
<div id="loginOfflineCancelIcon">X</div>
|
||||
<span id="loginOfflineCancelText">Cancel</span>
|
||||
</button>
|
||||
</div>
|
||||
<div id="loginContent">
|
||||
<form id="loginForm" style="margin-top: 2.5em;">
|
||||
<span id="loginSubheader">OFFLINE LOGIN</span>
|
||||
<div class="loginFieldContainer">
|
||||
<input id="loginOfflineUsername" class="loginField" type="text" placeholder="USERNAME"/>
|
||||
</div>
|
||||
<button id="loginOfflineButton" class="loginButton" enabled>
|
||||
<div id="loginOfflineButtonContent">
|
||||
LOGIN
|
||||
<svg id="loginSVG" viewBox="0 0 24.87 13.97">
|
||||
<defs>
|
||||
<style>.arrowLine{fill:none;stroke:#FFF;stroke-width:2px;transition: 0.25s ease;}</style>
|
||||
</defs>
|
||||
<polyline class="arrowLine" points="0.71 13.26 12.56 1.41 24.16 13.02"/>
|
||||
</svg>
|
||||
<div class="circle-loader">
|
||||
<div class="checkmark draw"></div>
|
||||
</div>
|
||||
</div>
|
||||
</button>
|
||||
</form>
|
||||
</div>
|
||||
<script src="./assets/js/scripts/loginOffline.js"></script>
|
||||
</div>
|
@ -1,34 +1,39 @@
|
||||
<div id="loginOptionsContainer" style="display: none;">
|
||||
<div id="loginOptionsContent">
|
||||
<div class="loginOptionsMainContent">
|
||||
<h2>Login Options</h2>
|
||||
<div class="loginOptionActions">
|
||||
<div class="loginOptionButtonContainer">
|
||||
<button id="loginOptionMicrosoft" class="loginOptionButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 23 23">
|
||||
<path fill="#f35325" d="M1 1h10v10H1z" />
|
||||
<path fill="#81bc06" d="M12 1h10v10H12z" />
|
||||
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
||||
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
||||
</svg>
|
||||
<span>Login with Microsoft</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="loginOptionButtonContainer">
|
||||
<button id="loginOptionMojang" class="loginOptionButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 9.677 9.667">
|
||||
<path d="M-26.332-12.098h2.715c-1.357.18-2.574 1.23-2.715 2.633z" fill="#fff" />
|
||||
<path d="M2.598.022h7.07L9.665 7c-.003 1.334-1.113 2.46-2.402 2.654H0V2.542C.134 1.2 1.3.195 2.598.022z" fill="#db2331" />
|
||||
<path d="M1.54 2.844c.314-.76 1.31-.46 1.954-.528.785-.083 1.503.272 2.1.758l.164-.9c.327.345.587.756.964 1.052.28.254.655-.342.86-.013.42.864.408 1.86.54 2.795l-.788-.373C6.9 4.17 5.126 3.052 3.656 3.685c-1.294.592-1.156 2.65.06 3.255 1.354.703 2.953.51 4.405.292-.07.42-.34.87-.834.816l-4.95.002c-.5.055-.886-.413-.838-.89l.04-4.315z" fill="#fff" />
|
||||
</svg>
|
||||
<span>Login with Mojang</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<div id="loginOptionCancelContainer" style="display: none;">
|
||||
<button id="loginOptionCancelButton">Cancel</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script src="./assets/js/scripts/loginOptions.js"></script>
|
||||
<div id="loginOptionsContainer" style="display: none;">
|
||||
<div id="loginOptionsContent">
|
||||
<div class="loginOptionsMainContent">
|
||||
<h2>Login Options</h2>
|
||||
<div class="loginOptionActions">
|
||||
<div class="loginOptionButtonContainer">
|
||||
<button id="loginOptionMicrosoft" class="loginOptionButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 23 23">
|
||||
<path fill="#f35325" d="M1 1h10v10H1z" />
|
||||
<path fill="#81bc06" d="M12 1h10v10H12z" />
|
||||
<path fill="#05a6f0" d="M1 12h10v10H1z" />
|
||||
<path fill="#ffba08" d="M12 12h10v10H12z" />
|
||||
</svg>
|
||||
<span>Login with Microsoft</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="loginOptionButtonContainer">
|
||||
<button id="loginOptionMojang" class="loginOptionButton">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" width="22" height="22" viewBox="0 0 9.677 9.667">
|
||||
<path d="M-26.332-12.098h2.715c-1.357.18-2.574 1.23-2.715 2.633z" fill="#fff" />
|
||||
<path d="M2.598.022h7.07L9.665 7c-.003 1.334-1.113 2.46-2.402 2.654H0V2.542C.134 1.2 1.3.195 2.598.022z" fill="#db2331" />
|
||||
<path d="M1.54 2.844c.314-.76 1.31-.46 1.954-.528.785-.083 1.503.272 2.1.758l.164-.9c.327.345.587.756.964 1.052.28.254.655-.342.86-.013.42.864.408 1.86.54 2.795l-.788-.373C6.9 4.17 5.126 3.052 3.656 3.685c-1.294.592-1.156 2.65.06 3.255 1.354.703 2.953.51 4.405.292-.07.42-.34.87-.834.816l-4.95.002c-.5.055-.886-.413-.838-.89l.04-4.315z" fill="#fff" />
|
||||
</svg>
|
||||
<span>Login with Mojang</span>
|
||||
</button>
|
||||
</div>
|
||||
<div class="loginOptionButtonContainer">
|
||||
<button id="loginOptionOffline" class="loginOptionButton">
|
||||
<span>Proceed Offline</span>
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!--<div id="loginOptionCancelContainer" style="display: none;">
|
||||
<button id="loginOptionCancelButton">Cancel</button>
|
||||
</div>-->
|
||||
</div>
|
||||
</div>
|
||||
<script src="./assets/js/scripts/loginOptions.js"></script>
|
||||
</div>
|
@ -68,6 +68,21 @@
|
||||
<!-- Mojang auth accounts populated here. -->
|
||||
</div>
|
||||
</div>
|
||||
<div class="settingsAuthAccountTypeContainer">
|
||||
<div class="settingsAuthAccountTypeHeader">
|
||||
<div class="settingsAuthAccountTypeHeaderLeft">
|
||||
<svg width="22px" height="22px" viewBox="0 0 64 64" enable-background="new 0 0 64 64" version="1.1" xml:space="preserve" xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink"><g id="Home"><path d="M62,21v39c0,1.1-0.9,2-2,2H4c-1.1,0-2-0.9-2-2V21c0-0.7,0.4-1.4,1-1.7l28-17c0.6-0.4,1.4-0.4,2.1,0l28,17 C61.6,19.6,62,20.3,62,21z" fill="#3F51B5"/><g><path d="M44,42v18c0,1.1-0.9,2-2,2H22c-1.1,0-2-0.9-2-2V42c0-6.6,5.4-12,12-12S44,35.4,44,42z" fill="#FFC10A"/></g></g><g id="Camera"/><g id="Mail"/><g id="Print"/><g id="Save"/><g id="Folder"/><g id="Search"/><g id="User"/><g id="Pin"/><g id="Calendar"/><g id="Gallery"/><g id="time"/><g id="Pin_1_"/><g id="Setting"/><g id="Player"/><g id="Lock"/><g id="Trash_Can"/><g id="Notification"/><g id="Record"/><g id="Shopping_Bag"/></svg>
|
||||
<span>Offline</span>
|
||||
</div>
|
||||
<div class="settingsAuthAccountTypeHeaderRight">
|
||||
<button class="settingsAddAuthAccount" id="settingsAddOfflineAccount">+ Add Offline Account</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="settingsCurrentAccounts" id="settingsCurrentOfflineAccounts">
|
||||
<!-- Offline auth accounts populated here. -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="settingsTabMinecraft" class="settingsTab" style="display: none;">
|
||||
<div class="settingsTabHeader">
|
||||
|
16678
package-lock.json
generated
16678
package-lock.json
generated
File diff suppressed because it is too large
Load Diff
@ -39,7 +39,9 @@
|
||||
"request": "^2.88.2",
|
||||
"semver": "^7.3.7",
|
||||
"tar-fs": "^2.1.1",
|
||||
"winreg": "^1.2.4"
|
||||
"winreg": "^1.2.4",
|
||||
"7zip-bin": "^5.2.0"
|
||||
|
||||
},
|
||||
"devDependencies": {
|
||||
"electron": "^19.0.10",
|
||||
|
Loading…
Reference in New Issue
Block a user