2018-06-12 07:25:36 +00:00
const os = require ( 'os' )
2018-05-31 03:32:51 +00:00
const settingsNavDone = document . getElementById ( 'settingsNavDone' )
2018-06-04 20:28:17 +00:00
// Account Management Tab
2018-05-31 02:22:17 +00:00
const settingsAddAccount = document . getElementById ( 'settingsAddAccount' )
const settingsCurrentAccounts = document . getElementById ( 'settingsCurrentAccounts' )
2018-06-04 20:28:17 +00:00
// Minecraft Tab
const settingsGameWidth = document . getElementById ( 'settingsGameWidth' )
const settingsGameHeight = document . getElementById ( 'settingsGameHeight' )
2018-06-12 02:11:05 +00:00
// Java Tab
const settingsMaxRAMRange = document . getElementById ( 'settingsMaxRAMRange' )
const settingsMinRAMRange = document . getElementById ( 'settingsMinRAMRange' )
2018-06-12 07:25:36 +00:00
const settingsMaxRAMLabel = document . getElementById ( 'settingsMaxRAMLabel' )
const settingsMinRAMLabel = document . getElementById ( 'settingsMinRAMLabel' )
const settingsMemoryTotal = document . getElementById ( 'settingsMemoryTotal' )
const settingsMemoryAvail = document . getElementById ( 'settingsMemoryAvail' )
2018-06-14 07:49:55 +00:00
const settingsJavaExecDetails = document . getElementById ( 'settingsJavaExecDetails' )
const settingsJavaExecVal = document . getElementById ( 'settingsJavaExecVal' )
const settingsJavaExecSel = document . getElementById ( 'settingsJavaExecSel' )
2018-06-12 02:11:05 +00:00
2018-06-04 20:28:17 +00:00
const settingsState = {
invalid : new Set ( )
}
2018-05-31 02:22:17 +00:00
/ * *
* General Settings Functions
* /
2018-06-04 20:28:17 +00:00
/ * *
* Bind value validators to the settings UI elements . These will
* validate against the criteria defined in the ConfigManager ( if
* and ) . If the value is invalid , the UI will reflect this and saving
* will be disabled until the value is corrected . This is an automated
* process . More complex UI may need to be bound separately .
* /
function initSettingsValidators ( ) {
const sEls = document . getElementById ( 'settingsContainer' ) . querySelectorAll ( '[cValue]' )
Array . from ( sEls ) . map ( ( v , index , arr ) => {
const vFn = ConfigManager [ 'validate' + v . getAttribute ( 'cValue' ) ]
if ( typeof vFn === 'function' ) {
if ( v . tagName === 'INPUT' ) {
if ( v . type === 'number' || v . type === 'text' ) {
v . addEventListener ( 'keyup' , ( e ) => {
const v = e . target
if ( ! vFn ( v . value ) ) {
settingsState . invalid . add ( v . id )
v . setAttribute ( 'error' , '' )
settingsSaveDisabled ( true )
} else {
if ( v . hasAttribute ( 'error' ) ) {
v . removeAttribute ( 'error' )
settingsState . invalid . delete ( v . id )
if ( settingsState . invalid . size === 0 ) {
settingsSaveDisabled ( false )
}
}
}
} )
}
}
}
} )
}
/ * *
* Load configuration values onto the UI . This is an automated process .
* /
function initSettingsValues ( ) {
const sEls = document . getElementById ( 'settingsContainer' ) . querySelectorAll ( '[cValue]' )
Array . from ( sEls ) . map ( ( v , index , arr ) => {
const gFn = ConfigManager [ 'get' + v . getAttribute ( 'cValue' ) ]
if ( typeof gFn === 'function' ) {
if ( v . tagName === 'INPUT' ) {
if ( v . type === 'number' || v . type === 'text' ) {
v . value = gFn ( )
2018-06-14 07:49:55 +00:00
// Special Conditions
const cVal = v . getAttribute ( 'cValue' )
if ( cVal === 'JavaExecutable' ) {
populateJavaExecDetails ( v . value )
}
2018-06-04 20:28:17 +00:00
} else if ( v . type === 'checkbox' ) {
v . checked = gFn ( )
}
2018-06-12 02:11:05 +00:00
} else if ( v . tagName === 'DIV' ) {
if ( v . classList . contains ( 'rangeSlider' ) ) {
2018-06-12 07:25:36 +00:00
// Special Conditions
const cVal = v . getAttribute ( 'cValue' )
if ( cVal === 'MinRAM' || cVal === 'MaxRAM' ) {
let val = gFn ( )
if ( val . endsWith ( 'M' ) ) {
val = Number ( val . substring ( 0 , val . length - 1 ) ) / 1000
} else {
val = Number . parseFloat ( val )
}
v . setAttribute ( 'value' , val )
} else {
v . setAttribute ( 'value' , Number . parseFloat ( gFn ( ) ) )
}
2018-06-12 02:11:05 +00:00
}
2018-06-04 20:28:17 +00:00
}
}
} )
}
/ * *
* Save the settings values .
* /
function saveSettingsValues ( ) {
const sEls = document . getElementById ( 'settingsContainer' ) . querySelectorAll ( '[cValue]' )
Array . from ( sEls ) . map ( ( v , index , arr ) => {
const sFn = ConfigManager [ 'set' + v . getAttribute ( 'cValue' ) ]
if ( typeof sFn === 'function' ) {
if ( v . tagName === 'INPUT' ) {
if ( v . type === 'number' || v . type === 'text' ) {
sFn ( v . value )
} else if ( v . type === 'checkbox' ) {
sFn ( v . checked )
2018-06-04 23:34:47 +00:00
// Special Conditions
const cVal = v . getAttribute ( 'cValue' )
if ( cVal === 'AllowPrerelease' ) {
changeAllowPrerelease ( v . checked )
}
2018-06-04 20:28:17 +00:00
}
2018-06-12 07:25:36 +00:00
} else if ( v . tagName === 'DIV' ) {
if ( v . classList . contains ( 'rangeSlider' ) ) {
// Special Conditions
const cVal = v . getAttribute ( 'cValue' )
if ( cVal === 'MinRAM' || cVal === 'MaxRAM' ) {
let val = Number ( v . getAttribute ( 'value' ) )
if ( val % 1 > 0 ) {
val = val * 1000 + 'M'
} else {
val = val + 'G'
}
sFn ( val )
} else {
sFn ( v . getAttribute ( 'value' ) )
}
}
2018-06-04 20:28:17 +00:00
}
}
} )
}
2018-05-30 20:00:07 +00:00
let selectedTab = 'settingsTabAccount'
2018-05-31 02:22:17 +00:00
/ * *
* Bind functionality for the settings navigation items .
* /
2018-05-30 20:00:07 +00:00
function setupSettingsTabs ( ) {
Array . from ( document . getElementsByClassName ( 'settingsNavItem' ) ) . map ( ( val ) => {
val . onclick = ( e ) => {
if ( val . hasAttribute ( 'selected' ) ) {
return
}
const navItems = document . getElementsByClassName ( 'settingsNavItem' )
for ( let i = 0 ; i < navItems . length ; i ++ ) {
if ( navItems [ i ] . hasAttribute ( 'selected' ) ) {
navItems [ i ] . removeAttribute ( 'selected' )
}
}
val . setAttribute ( 'selected' , '' )
let prevTab = selectedTab
selectedTab = val . getAttribute ( 'rSc' )
$ ( ` # ${ prevTab } ` ) . fadeOut ( 250 , ( ) => {
$ ( ` # ${ selectedTab } ` ) . fadeIn ( 250 )
} )
}
} )
}
2018-06-04 20:28:17 +00:00
/ * *
* Set if the settings save ( done ) button is disabled .
*
* @ param { boolean } v True to disable , false to enable .
* /
function settingsSaveDisabled ( v ) {
settingsNavDone . disabled = v
}
2018-05-31 03:32:51 +00:00
/* Closes the settings view and saves all data. */
settingsNavDone . onclick = ( ) => {
2018-06-04 20:28:17 +00:00
saveSettingsValues ( )
ConfigManager . save ( )
2018-05-31 03:32:51 +00:00
switchView ( getCurrentView ( ) , VIEWS . landing )
}
2018-05-31 02:22:17 +00:00
/ * *
* Account Management Tab
* /
// Bind the add account button.
settingsAddAccount . onclick = ( e ) => {
switchView ( getCurrentView ( ) , VIEWS . login , 500 , 500 , ( ) => {
loginViewOnCancel = VIEWS . settings
loginViewOnSuccess = VIEWS . settings
loginCancelEnabled ( true )
} )
}
/ * *
* Bind functionality for the account selection buttons . If another account
* is selected , the UI of the previously selected account will be updated .
* /
function bindAuthAccountSelect ( ) {
Array . from ( document . getElementsByClassName ( 'settingsAuthAccountSelect' ) ) . map ( ( val ) => {
val . onclick = ( e ) => {
if ( val . hasAttribute ( 'selected' ) ) {
return
}
const selectBtns = document . getElementsByClassName ( 'settingsAuthAccountSelect' )
for ( let i = 0 ; i < selectBtns . length ; i ++ ) {
if ( selectBtns [ i ] . hasAttribute ( 'selected' ) ) {
selectBtns [ i ] . removeAttribute ( 'selected' )
selectBtns [ i ] . innerHTML = 'Select Account'
}
}
val . setAttribute ( 'selected' , '' )
val . innerHTML = 'Selected Account ✔'
2018-05-31 03:32:51 +00:00
setSelectedAccount ( val . closest ( '.settingsAuthAccount' ) . getAttribute ( 'uuid' ) )
2018-05-31 02:22:17 +00:00
}
} )
}
/ * *
* Bind functionality for the log out button . If the logged out account was
* the selected account , another account will be selected and the UI will
* be updated accordingly .
* /
function bindAuthAccountLogOut ( ) {
Array . from ( document . getElementsByClassName ( 'settingsAuthAccountLogOut' ) ) . map ( ( val ) => {
val . onclick = ( e ) => {
2018-05-31 03:32:51 +00:00
let isLastAccount = false
if ( Object . keys ( ConfigManager . getAuthAccounts ( ) ) . length === 1 ) {
isLastAccount = true
setOverlayContent (
'Warning<br>This is Your Last Account' ,
'In order to use the launcher you must be logged into at least one account. You will need to login again after.<br><br>Are you sure you want to log out?' ,
'I\'m Sure' ,
'Cancel'
)
setOverlayHandler ( ( ) => {
processLogOut ( val , isLastAccount )
switchView ( getCurrentView ( ) , VIEWS . login )
toggleOverlay ( false )
} )
setDismissHandler ( ( ) => {
toggleOverlay ( false )
} )
toggleOverlay ( true , true )
} else {
processLogOut ( val , isLastAccount )
}
}
} )
}
/ * *
* Process a log out .
*
* @ param { Element } val The log out button element .
* @ param { boolean } isLastAccount If this logout is on the last added account .
* /
function processLogOut ( val , isLastAccount ) {
const parent = val . closest ( '.settingsAuthAccount' )
const uuid = parent . getAttribute ( 'uuid' )
const prevSelAcc = ConfigManager . getSelectedAccount ( )
AuthManager . removeAccount ( uuid ) . then ( ( ) => {
if ( ! isLastAccount && uuid === prevSelAcc . uuid ) {
const selAcc = ConfigManager . getSelectedAccount ( )
refreshAuthAccountSelected ( selAcc . uuid )
updateSelectedAccount ( selAcc )
validateSelectedAccount ( )
2018-05-31 02:22:17 +00:00
}
} )
2018-05-31 03:32:51 +00:00
$ ( parent ) . fadeOut ( 250 , ( ) => {
parent . remove ( )
} )
2018-05-31 02:22:17 +00:00
}
/ * *
* Refreshes the status of the selected account on the auth account
* elements .
*
* @ param { string } uuid The UUID of the new selected account .
* /
function refreshAuthAccountSelected ( uuid ) {
Array . from ( document . getElementsByClassName ( 'settingsAuthAccount' ) ) . map ( ( val ) => {
const selBtn = val . getElementsByClassName ( 'settingsAuthAccountSelect' ) [ 0 ]
if ( uuid === val . getAttribute ( 'uuid' ) ) {
selBtn . setAttribute ( 'selected' , '' )
selBtn . innerHTML = 'Selected Account ✔'
} else {
if ( selBtn . hasAttribute ( 'selected' ) ) {
selBtn . removeAttribute ( 'selected' )
}
selBtn . innerHTML = 'Select Account'
}
} )
}
/ * *
* Add auth account elements for each one stored in the authentication database .
* /
function populateAuthAccounts ( ) {
const authAccounts = ConfigManager . getAuthAccounts ( )
const authKeys = Object . keys ( authAccounts )
const selectedUUID = ConfigManager . getSelectedAccount ( ) . uuid
let authAccountStr = ` `
authKeys . map ( ( val ) => {
const acc = authAccounts [ val ]
authAccountStr += ` <div class="settingsAuthAccount" uuid=" ${ acc . uuid } ">
< div class = "settingsAuthAccountLeft" >
< img class = "settingsAuthAccountImage" alt = "${acc.displayName}" src = "https://crafatar.com/renders/body/${acc.uuid}?scale=3&default=MHF_Steve&overlay" >
< / d i v >
< div class = "settingsAuthAccountRight" >
< div class = "settingsAuthAccountDetails" >
< div class = "settingsAuthAccountDetailPane" >
< div class = "settingsAuthAccountDetailTitle" > Username < / d i v >
< div class = "settingsAuthAccountDetailValue" > $ { acc . displayName } < / d i v >
< / d i v >
< div class = "settingsAuthAccountDetailPane" >
< div class = "settingsAuthAccountDetailTitle" > $ { acc . displayName === acc . username ? 'UUID' : 'Email' } < / d i v >
< div class = "settingsAuthAccountDetailValue" > $ { acc . displayName === acc . username ? acc . uuid : acc . username } < / d i v >
< / d i v >
< / d i v >
< div class = "settingsAuthAccountActions" >
< button class = "settingsAuthAccountSelect" $ { selectedUUID === acc . uuid ? 'selected>Selected Account ✔' : '>Select Account' } < / b u t t o n >
< div class = "settingsAuthAccountWrapper" >
< button class = "settingsAuthAccountLogOut" > Log Out < / b u t t o n >
< / d i v >
< / d i v >
< / d i v >
< / d i v > `
} )
settingsCurrentAccounts . innerHTML = authAccountStr
}
function prepareAccountsTab ( ) {
populateAuthAccounts ( )
bindAuthAccountSelect ( )
bindAuthAccountLogOut ( )
}
2018-06-04 20:28:17 +00:00
/ * *
* Minecraft Tab
* /
/ * *
* Disable decimals , negative signs , and scientific notation .
* /
settingsGameWidth . addEventListener ( 'keydown' , ( e ) => {
if ( /[-\.eE]/ . test ( e . key ) ) {
e . preventDefault ( )
}
} )
settingsGameHeight . addEventListener ( 'keydown' , ( e ) => {
if ( /[-\.eE]/ . test ( e . key ) ) {
e . preventDefault ( )
}
} )
2018-06-12 02:11:05 +00:00
/ * *
* Java Tab
* /
settingsMaxRAMRange . setAttribute ( 'max' , ConfigManager . getAbsoluteMaxRAM ( ) )
settingsMaxRAMRange . setAttribute ( 'min' , ConfigManager . getAbsoluteMinRAM ( ) )
settingsMinRAMRange . setAttribute ( 'max' , ConfigManager . getAbsoluteMaxRAM ( ) )
settingsMinRAMRange . setAttribute ( 'min' , ConfigManager . getAbsoluteMinRAM ( ) )
settingsMinRAMRange . onchange = ( e ) => {
const sMaxV = Number ( settingsMaxRAMRange . getAttribute ( 'value' ) )
const sMinV = Number ( settingsMinRAMRange . getAttribute ( 'value' ) )
2018-06-12 07:48:36 +00:00
const bar = e . target . getElementsByClassName ( 'rangeSliderBar' ) [ 0 ]
const max = ( os . totalmem ( ) - 1000000000 ) / 1000000000
if ( sMinV >= max / 2 ) {
bar . style . background = '#e86060'
} else if ( sMinV >= max / 4 ) {
bar . style . background = '#e8e18b'
} else {
bar . style . background = null
}
2018-06-12 02:11:05 +00:00
if ( sMaxV < sMinV ) {
const sliderMeta = calculateRangeSliderMeta ( settingsMaxRAMRange )
updateRangedSlider ( settingsMaxRAMRange , sMinV ,
2018-06-12 07:48:36 +00:00
( ( sMinV - sliderMeta . min ) / sliderMeta . step ) * sliderMeta . inc )
2018-06-12 07:25:36 +00:00
settingsMaxRAMLabel . innerHTML = sMinV . toFixed ( 1 ) + 'G'
2018-06-12 02:11:05 +00:00
}
2018-06-12 07:25:36 +00:00
settingsMinRAMLabel . innerHTML = sMinV . toFixed ( 1 ) + 'G'
2018-06-12 02:11:05 +00:00
}
2018-06-12 07:25:36 +00:00
2018-06-12 02:11:05 +00:00
settingsMaxRAMRange . onchange = ( e ) => {
const sMaxV = Number ( settingsMaxRAMRange . getAttribute ( 'value' ) )
const sMinV = Number ( settingsMinRAMRange . getAttribute ( 'value' ) )
2018-06-12 07:48:36 +00:00
const bar = e . target . getElementsByClassName ( 'rangeSliderBar' ) [ 0 ]
const max = ( os . totalmem ( ) - 1000000000 ) / 1000000000
if ( sMaxV >= max / 2 ) {
bar . style . background = '#e86060'
} else if ( sMaxV >= max / 4 ) {
bar . style . background = '#e8e18b'
} else {
bar . style . background = null
}
2018-06-12 02:11:05 +00:00
if ( sMaxV < sMinV ) {
2018-06-12 07:25:36 +00:00
const sliderMeta = calculateRangeSliderMeta ( settingsMaxRAMRange )
updateRangedSlider ( settingsMinRAMRange , sMaxV ,
2018-06-12 07:48:36 +00:00
( ( sMaxV - sliderMeta . min ) / sliderMeta . step ) * sliderMeta . inc )
2018-06-12 07:25:36 +00:00
settingsMinRAMLabel . innerHTML = sMaxV . toFixed ( 1 ) + 'G'
2018-06-12 02:11:05 +00:00
}
2018-06-12 07:25:36 +00:00
settingsMaxRAMLabel . innerHTML = sMaxV . toFixed ( 1 ) + 'G'
2018-06-12 02:11:05 +00:00
}
2018-06-14 07:49:55 +00:00
settingsJavaExecSel . onchange = ( e ) => {
settingsJavaExecVal . value = settingsJavaExecSel . files [ 0 ] . path
populateJavaExecDetails ( settingsJavaExecVal . value )
}
function populateJavaExecDetails ( execPath ) {
AssetGuard . _validateJavaBinary ( execPath ) . then ( v => {
if ( v . valid ) {
settingsJavaExecDetails . innerHTML = ` Selected: Java ${ v . version . major } Update ${ v . version . update } (x ${ v . arch } ) `
} else {
settingsJavaExecDetails . innerHTML = 'Invalid Selection'
}
} )
}
2018-06-12 02:11:05 +00:00
function calculateRangeSliderMeta ( v ) {
const val = {
max : Number ( v . getAttribute ( 'max' ) ) ,
min : Number ( v . getAttribute ( 'min' ) ) ,
step : Number ( v . getAttribute ( 'step' ) ) ,
}
2018-06-12 07:48:36 +00:00
val . ticks = ( val . max - val . min ) / val . step
2018-06-12 02:11:05 +00:00
val . inc = 100 / val . ticks
return val
}
function bindRangeSlider ( ) {
Array . from ( document . getElementsByClassName ( 'rangeSlider' ) ) . map ( ( v ) => {
const track = v . getElementsByClassName ( 'rangeSliderTrack' ) [ 0 ]
const value = v . getAttribute ( 'value' )
const sliderMeta = calculateRangeSliderMeta ( v )
updateRangedSlider ( v , value ,
2018-06-12 07:48:36 +00:00
( ( value - sliderMeta . min ) / sliderMeta . step ) * sliderMeta . inc )
2018-06-12 02:11:05 +00:00
track . onmousedown = ( e ) => {
document . onmouseup = ( e ) => {
document . onmousemove = null
document . onmouseup = null
}
document . onmousemove = ( e ) => {
const diff = e . pageX - v . offsetLeft - track . offsetWidth / 2
if ( diff >= 0 && diff <= v . offsetWidth - track . offsetWidth / 2 ) {
const perc = ( diff / v . offsetWidth ) * 100
const notch = Number ( perc / sliderMeta . inc ) . toFixed ( 0 ) * sliderMeta . inc
2018-06-12 07:48:36 +00:00
2018-06-12 02:11:05 +00:00
if ( Math . abs ( perc - notch ) < sliderMeta . inc / 2 ) {
2018-06-12 07:48:36 +00:00
updateRangedSlider ( v , sliderMeta . min + ( sliderMeta . step * ( notch / sliderMeta . inc ) ) , notch )
2018-06-12 02:11:05 +00:00
}
}
}
}
} )
}
function updateRangedSlider ( element , value , notch ) {
const oldVal = element . getAttribute ( 'value' )
const bar = element . getElementsByClassName ( 'rangeSliderBar' ) [ 0 ]
const track = element . getElementsByClassName ( 'rangeSliderTrack' ) [ 0 ]
element . setAttribute ( 'value' , value )
const event = new MouseEvent ( 'change' , {
target : element ,
type : 'change' ,
bubbles : false ,
cancelable : true
} )
let cancelled = ! element . dispatchEvent ( event )
if ( ! cancelled ) {
track . style . left = notch + '%'
bar . style . width = notch + '%'
} else {
element . setAttribute ( 'value' , oldVal )
}
}
2018-06-12 07:25:36 +00:00
function bindMemoryStatus ( ) {
settingsMemoryTotal . innerHTML = Number ( ( os . totalmem ( ) - 1000000000 ) / 1000000000 ) . toFixed ( 1 ) + 'G'
settingsMemoryAvail . innerHTML = Number ( os . freemem ( ) / 1000000000 ) . toFixed ( 1 ) + 'G'
}
2018-06-12 02:11:05 +00:00
function prepareJavaTab ( ) {
bindRangeSlider ( )
2018-06-12 07:25:36 +00:00
bindMemoryStatus ( )
2018-06-12 02:11:05 +00:00
}
2018-05-31 02:22:17 +00:00
/ * *
* Settings preparation functions .
* /
/ * *
* Prepare the entire settings UI .
2018-06-04 20:28:17 +00:00
*
* @ param { boolean } first Whether or not it is the first load .
2018-05-31 02:22:17 +00:00
* /
2018-06-04 20:28:17 +00:00
function prepareSettings ( first = false ) {
if ( first ) {
setupSettingsTabs ( )
initSettingsValidators ( )
}
initSettingsValues ( )
2018-05-31 02:22:17 +00:00
prepareAccountsTab ( )
2018-06-12 02:11:05 +00:00
prepareJavaTab ( )
2018-05-31 02:22:17 +00:00
}
// Prepare the settings UI on startup.
2018-06-04 20:28:17 +00:00
prepareSettings ( true )