|
|
|
@@ -24,6 +24,11 @@ const state = {
|
|
|
|
packs: [],
|
|
|
|
packs: [],
|
|
|
|
selectedPackKey: null,
|
|
|
|
selectedPackKey: null,
|
|
|
|
mode: null, // 'single' | 'multi'
|
|
|
|
mode: null, // 'single' | 'multi'
|
|
|
|
|
|
|
|
// mode==='multi' 일 때만 의미가 있다.
|
|
|
|
|
|
|
|
// 'host' → 서버를 직접 연다. 기존 멀티 흐름 (step3 + step4) 그대로.
|
|
|
|
|
|
|
|
// 'participant' → 친구 서버에 접속만 한다. step3 (서버 설치) 를 건너뛰고
|
|
|
|
|
|
|
|
// client 측에서도 맵은 받지 않는다 (참가자라 서버에 이미 있음).
|
|
|
|
|
|
|
|
role: null, // 'host' | 'participant' | null
|
|
|
|
serverInstall: {
|
|
|
|
serverInstall: {
|
|
|
|
path: '',
|
|
|
|
path: '',
|
|
|
|
jdk: '',
|
|
|
|
jdk: '',
|
|
|
|
@@ -154,33 +159,71 @@ function renderStep2() {
|
|
|
|
'<button id="single" type="button" data-mode="single"><strong>' + tt('step2.singleTitle') + '</strong><br><small>' + tt('step2.singleHint') + '</small></button>' +
|
|
|
|
'<button id="single" type="button" data-mode="single"><strong>' + tt('step2.singleTitle') + '</strong><br><small>' + tt('step2.singleHint') + '</small></button>' +
|
|
|
|
'<button id="multi" type="button" data-mode="multi"><strong>' + tt('step2.multiTitle') + '</strong><br><small>' + tt('step2.multiHint') + '</small></button>' +
|
|
|
|
'<button id="multi" type="button" data-mode="multi"><strong>' + tt('step2.multiTitle') + '</strong><br><small>' + tt('step2.multiHint') + '</small></button>' +
|
|
|
|
'</div>' +
|
|
|
|
'</div>' +
|
|
|
|
|
|
|
|
'<div id="roleSection" hidden style="margin-top:16px;">' +
|
|
|
|
|
|
|
|
'<h3>' + tt('step2.roleHeading') + '</h3>' +
|
|
|
|
|
|
|
|
'<div class="cardChoice">' +
|
|
|
|
|
|
|
|
'<button type="button" data-role="host"><strong>' + tt('step2.hostTitle') + '</strong><br><small>' + tt('step2.hostHint') + '</small></button>' +
|
|
|
|
|
|
|
|
'<button type="button" data-role="participant"><strong>' + tt('step2.participantTitle') + '</strong><br><small>' + tt('step2.participantHint') + '</small></button>' +
|
|
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
|
|
'</div>' +
|
|
|
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next" disabled>' + tt('common.next') + '</button></div>'
|
|
|
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next" disabled>' + tt('common.next') + '</button></div>'
|
|
|
|
pageHost.appendChild(section)
|
|
|
|
pageHost.appendChild(section)
|
|
|
|
var nextBtn = section.querySelector('#next')
|
|
|
|
var nextBtn = section.querySelector('#next')
|
|
|
|
var modeButtons = section.querySelectorAll('[data-mode]')
|
|
|
|
var modeButtons = section.querySelectorAll('[data-mode]')
|
|
|
|
|
|
|
|
var roleSection = section.querySelector('#roleSection')
|
|
|
|
|
|
|
|
var roleButtons = section.querySelectorAll('[data-role]')
|
|
|
|
|
|
|
|
|
|
|
|
function applySelection(mode) {
|
|
|
|
function applyMode(mode) {
|
|
|
|
state.mode = mode
|
|
|
|
state.mode = mode
|
|
|
|
modeButtons.forEach(function (btn) {
|
|
|
|
modeButtons.forEach(function (btn) {
|
|
|
|
if (btn.getAttribute('data-mode') === mode) btn.classList.add('selected')
|
|
|
|
if (btn.getAttribute('data-mode') === mode) btn.classList.add('selected')
|
|
|
|
else btn.classList.remove('selected')
|
|
|
|
else btn.classList.remove('selected')
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
if (mode === 'multi') {
|
|
|
|
|
|
|
|
roleSection.hidden = false
|
|
|
|
|
|
|
|
// 역할이 이미 골라져 있으면 그대로, 아니면 사용자가 골라야 next 활성화.
|
|
|
|
|
|
|
|
nextBtn.disabled = !state.role
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
roleSection.hidden = true
|
|
|
|
|
|
|
|
state.role = null
|
|
|
|
|
|
|
|
roleButtons.forEach(function (btn) { btn.classList.remove('selected') })
|
|
|
|
|
|
|
|
nextBtn.disabled = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function applyRole(role) {
|
|
|
|
|
|
|
|
state.role = role
|
|
|
|
|
|
|
|
roleButtons.forEach(function (btn) {
|
|
|
|
|
|
|
|
if (btn.getAttribute('data-role') === role) btn.classList.add('selected')
|
|
|
|
|
|
|
|
else btn.classList.remove('selected')
|
|
|
|
|
|
|
|
})
|
|
|
|
nextBtn.disabled = false
|
|
|
|
nextBtn.disabled = false
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
modeButtons.forEach(function (btn) {
|
|
|
|
modeButtons.forEach(function (btn) {
|
|
|
|
btn.addEventListener('click', function () {
|
|
|
|
btn.addEventListener('click', function () {
|
|
|
|
applySelection(btn.getAttribute('data-mode'))
|
|
|
|
applyMode(btn.getAttribute('data-mode'))
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
roleButtons.forEach(function (btn) {
|
|
|
|
|
|
|
|
btn.addEventListener('click', function () {
|
|
|
|
|
|
|
|
applyRole(btn.getAttribute('data-role'))
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
if (state.mode === 'single' || state.mode === 'multi') applySelection(state.mode)
|
|
|
|
if (state.mode === 'single' || state.mode === 'multi') {
|
|
|
|
|
|
|
|
applyMode(state.mode)
|
|
|
|
|
|
|
|
if (state.mode === 'multi' && state.role) applyRole(state.role)
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
nextBtn.addEventListener('click', function () {
|
|
|
|
nextBtn.addEventListener('click', function () {
|
|
|
|
if (!state.mode) return
|
|
|
|
if (!state.mode) return
|
|
|
|
|
|
|
|
if (state.mode === 'multi' && !state.role) return
|
|
|
|
state.stepDone[2] = true
|
|
|
|
state.stepDone[2] = true
|
|
|
|
if (state.mode === 'single') renderStep4()
|
|
|
|
// 멀티+호스트 만 서버 설치(step3) 를 거친다.
|
|
|
|
else renderStep3()
|
|
|
|
// 싱글, 멀티+참가자 는 곧장 클라이언트(step4) 로.
|
|
|
|
|
|
|
|
if (state.mode === 'multi' && state.role === 'host') renderStep3()
|
|
|
|
|
|
|
|
else renderStep4()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
section.querySelector('#back').addEventListener('click', renderStep1)
|
|
|
|
section.querySelector('#back').addEventListener('click', renderStep1)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -446,13 +489,10 @@ function renderSubStep33(host, back, done) {
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
// EULA 동의 팝업. resolve(true) = 동의, resolve(false) = 비동의/창 닫힘.
|
|
|
|
// EULA 동의 팝업. resolve(true) = 동의, resolve(false) = 비동의/창 닫힘.
|
|
|
|
async function openEulaPopup(installPath) {
|
|
|
|
// eula.txt 의 내용과 무관하게 항상 minecraft.net 의 공식 EULA 페이지를 받아서
|
|
|
|
var read = await installerApi.readEula(installPath)
|
|
|
|
// 표시한다 — 사용자가 실제 서버 약관을 보고 동의하도록.
|
|
|
|
|
|
|
|
async function openEulaPopup(_installPath) {
|
|
|
|
var bodyHtml = ''
|
|
|
|
var bodyHtml = ''
|
|
|
|
if (read.exists) {
|
|
|
|
|
|
|
|
bodyHtml = '<p class="formMessage">' + tt('step3.eulaModal.fromFile') + '</p>' +
|
|
|
|
|
|
|
|
'<pre class="eulaPre">' + escapeHtml(read.content) + '</pre>'
|
|
|
|
|
|
|
|
} else {
|
|
|
|
|
|
|
|
var fetched = await installerApi.fetchMinecraftEula()
|
|
|
|
var fetched = await installerApi.fetchMinecraftEula()
|
|
|
|
if (fetched.html) {
|
|
|
|
if (fetched.html) {
|
|
|
|
bodyHtml = '<p class="formMessage">' + tt('step3.eulaModal.fromMojang', { url: fetched.url }) + '</p>' +
|
|
|
|
bodyHtml = '<p class="formMessage">' + tt('step3.eulaModal.fromMojang', { url: fetched.url }) + '</p>' +
|
|
|
|
@@ -460,7 +500,6 @@ async function openEulaPopup(installPath) {
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
bodyHtml = '<p class="formMessage error">' + tt('step3.eulaModal.loadFailed') + '</p>'
|
|
|
|
bodyHtml = '<p class="formMessage error">' + tt('step3.eulaModal.loadFailed') + '</p>'
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
return new Promise(function (resolve) {
|
|
|
|
var overlay = document.createElement('div')
|
|
|
|
var overlay = document.createElement('div')
|
|
|
|
overlay.className = 'modalOverlay'
|
|
|
|
overlay.className = 'modalOverlay'
|
|
|
|
@@ -491,12 +530,6 @@ async function openEulaPopup(installPath) {
|
|
|
|
})
|
|
|
|
})
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function escapeHtml(text) {
|
|
|
|
|
|
|
|
return String(text).replace(/[&<>"']/g, function (ch) {
|
|
|
|
|
|
|
|
return { '&': '&', '<': '<', '>': '>', '"': '"', "'": ''' }[ch]
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function escapeAttr(text) {
|
|
|
|
function escapeAttr(text) {
|
|
|
|
return String(text).replace(/&/g, '&').replace(/"/g, '"')
|
|
|
|
return String(text).replace(/&/g, '&').replace(/"/g, '"')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
@@ -535,6 +568,14 @@ function renderSubStep35(host, back, done) {
|
|
|
|
var runBtn = host.querySelector('#run')
|
|
|
|
var runBtn = host.querySelector('#run')
|
|
|
|
host.querySelector('#back').addEventListener('click', back)
|
|
|
|
host.querySelector('#back').addEventListener('click', back)
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 25565 는 마인크래프트 자바판 기본 포트라 클라이언트에서 생략 가능 →
|
|
|
|
|
|
|
|
// 사용자에게도 ip 만 보여주는 게 깔끔하다.
|
|
|
|
|
|
|
|
function formatServerAddress(ip, port) {
|
|
|
|
|
|
|
|
var safeIp = ip || tt('step3.sub35.ipUnknown')
|
|
|
|
|
|
|
|
if (Number(port) === 25565) return safeIp
|
|
|
|
|
|
|
|
return safeIp + ':' + port
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
async function runCheck() {
|
|
|
|
async function runCheck() {
|
|
|
|
runBtn.disabled = true
|
|
|
|
runBtn.disabled = true
|
|
|
|
resultMsg.classList.remove('success', 'warn', 'error')
|
|
|
|
resultMsg.classList.remove('success', 'warn', 'error')
|
|
|
|
@@ -543,16 +584,16 @@ function renderSubStep35(host, back, done) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
var result = await installerApi.checkPortForward(port)
|
|
|
|
var result = await installerApi.checkPortForward(port)
|
|
|
|
state.serverInstall.portStatus = result
|
|
|
|
state.serverInstall.portStatus = result
|
|
|
|
|
|
|
|
var address = formatServerAddress(result.externalIp, result.port)
|
|
|
|
if (result.status === 'preForwarded') {
|
|
|
|
if (result.status === 'preForwarded') {
|
|
|
|
resultMsg.innerHTML = tt('step3.sub35.preForwarded', { ip: result.externalIp, port: result.port })
|
|
|
|
resultMsg.innerHTML = tt('step3.sub35.preForwarded', { address: address })
|
|
|
|
resultMsg.classList.add('success')
|
|
|
|
resultMsg.classList.add('success')
|
|
|
|
} else if (result.status === 'upnpOk') {
|
|
|
|
} else if (result.status === 'upnpOk') {
|
|
|
|
resultMsg.innerHTML = tt('step3.sub35.upnpOk', { ip: result.externalIp, port: result.port })
|
|
|
|
resultMsg.innerHTML = tt('step3.sub35.upnpOk', { address: address })
|
|
|
|
resultMsg.classList.add('success')
|
|
|
|
resultMsg.classList.add('success')
|
|
|
|
} else {
|
|
|
|
} else {
|
|
|
|
var ip = result.externalIp || tt('step3.sub35.ipUnknown')
|
|
|
|
|
|
|
|
resultMsg.innerHTML = (result.message || tt('step3.sub35.manualHint')) +
|
|
|
|
resultMsg.innerHTML = (result.message || tt('step3.sub35.manualHint')) +
|
|
|
|
tt('step3.sub35.manualDetail', { ip: ip, port: result.port })
|
|
|
|
tt('step3.sub35.manualDetail', { address: address })
|
|
|
|
resultMsg.classList.add('warn')
|
|
|
|
resultMsg.classList.add('warn')
|
|
|
|
}
|
|
|
|
}
|
|
|
|
nextBtn.disabled = false
|
|
|
|
nextBtn.disabled = false
|
|
|
|
@@ -581,64 +622,25 @@ function renderStep4() {
|
|
|
|
'<div class="subStep" id="subHost"></div>'
|
|
|
|
'<div class="subStep" id="subHost"></div>'
|
|
|
|
pageHost.appendChild(section)
|
|
|
|
pageHost.appendChild(section)
|
|
|
|
var subHost = section.querySelector('#subHost')
|
|
|
|
var subHost = section.querySelector('#subHost')
|
|
|
|
function backToPrevStep() { if (state.mode === 'multi') renderStep3(); else renderStep2() }
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function show41() { subHost.innerHTML = ''; renderSubStep41(subHost, pack, backToPrevStep, show42) }
|
|
|
|
// 플랫폼 선택 UI 는 더 이상 보여주지 않는다. 음악퀴즈에 지정된 플랫폼이
|
|
|
|
function show42() { subHost.innerHTML = ''; renderSubStep42(subHost, show41, goStep5) }
|
|
|
|
// 바닐라가 아니면 자동으로 설치하고, 바닐라면 건너뛴다 — 사용자가 고를 일이 없다.
|
|
|
|
|
|
|
|
var platformType = pack ? pack.pack.platform.type : 'vanilla'
|
|
|
|
|
|
|
|
state.client.installPlatform = platformType !== 'vanilla'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
// 멀티+호스트 만 step3 (서버 설치) 를 거쳤으므로 거기로 돌아간다.
|
|
|
|
|
|
|
|
// 싱글 / 멀티+참가자 는 step2 로 되돌아간다.
|
|
|
|
|
|
|
|
function backToPrevStep() {
|
|
|
|
|
|
|
|
if (state.mode === 'multi' && state.role === 'host') renderStep3()
|
|
|
|
|
|
|
|
else renderStep2()
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function show42() { subHost.innerHTML = ''; renderSubStep42(subHost, backToPrevStep, goStep5) }
|
|
|
|
function goStep5() {
|
|
|
|
function goStep5() {
|
|
|
|
state.stepDone[4] = true
|
|
|
|
state.stepDone[4] = true
|
|
|
|
renderStep5()
|
|
|
|
renderStep5()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
show41()
|
|
|
|
show42()
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function renderSubStep41(host, pack, back, done) {
|
|
|
|
|
|
|
|
var platformType = pack ? pack.pack.platform.type : 'vanilla'
|
|
|
|
|
|
|
|
if (platformType === 'vanilla') {
|
|
|
|
|
|
|
|
state.client.installPlatform = false
|
|
|
|
|
|
|
|
host.innerHTML =
|
|
|
|
|
|
|
|
'<h3>' + tt('step4.sub41.heading') + '</h3>' +
|
|
|
|
|
|
|
|
'<p class="formMessage">' + tt('step4.sub41.vanillaInfo') + '</p>' +
|
|
|
|
|
|
|
|
'<p class="formMessage">' + tt('step4.sub41.vanillaNoInstall') + '</p>' +
|
|
|
|
|
|
|
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next">' + tt('common.next') + '</button></div>'
|
|
|
|
|
|
|
|
host.querySelector('#back').addEventListener('click', back)
|
|
|
|
|
|
|
|
host.querySelector('#next').addEventListener('click', done)
|
|
|
|
|
|
|
|
return
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
host.innerHTML =
|
|
|
|
|
|
|
|
'<h3>' + tt('step4.sub41.heading') + '</h3>' +
|
|
|
|
|
|
|
|
'<p class="formMessage">' + tt('step4.sub41.info', { platform: platformType }) + '</p>' +
|
|
|
|
|
|
|
|
'<div class="cardChoice">' +
|
|
|
|
|
|
|
|
'<button type="button" data-choice="install"><strong>' + tt('step4.sub41.installTitle') + '</strong><br><small>' + tt('step4.sub41.installHint', { platform: platformType }) + '</small></button>' +
|
|
|
|
|
|
|
|
'<button type="button" data-choice="skip"><strong>' + tt('step4.sub41.skipTitle') + '</strong><br><small>' + tt('step4.sub41.skipHint') + '</small></button>' +
|
|
|
|
|
|
|
|
'</div>' +
|
|
|
|
|
|
|
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="next" disabled>' + tt('common.next') + '</button></div>'
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
var nextBtn = host.querySelector('#next')
|
|
|
|
|
|
|
|
var choiceButtons = host.querySelectorAll('[data-choice]')
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function applyChoice(choice) {
|
|
|
|
|
|
|
|
state.client.installPlatform = choice === 'install'
|
|
|
|
|
|
|
|
choiceButtons.forEach(function (btn) {
|
|
|
|
|
|
|
|
if (btn.getAttribute('data-choice') === choice) btn.classList.add('selected')
|
|
|
|
|
|
|
|
else btn.classList.remove('selected')
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
nextBtn.disabled = false
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
choiceButtons.forEach(function (btn) {
|
|
|
|
|
|
|
|
btn.addEventListener('click', function () {
|
|
|
|
|
|
|
|
applyChoice(btn.getAttribute('data-choice'))
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (typeof state.client.installPlatform === 'boolean') {
|
|
|
|
|
|
|
|
applyChoice(state.client.installPlatform ? 'install' : 'skip')
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
host.querySelector('#back').addEventListener('click', back)
|
|
|
|
|
|
|
|
nextBtn.addEventListener('click', done)
|
|
|
|
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
function renderSubStep42(host, back, done) {
|
|
|
|
function renderSubStep42(host, back, done) {
|
|
|
|
@@ -665,7 +667,9 @@ function renderSubStep42(host, back, done) {
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
await installerApi.installClient({
|
|
|
|
await installerApi.installClient({
|
|
|
|
packKey: state.selectedPackKey,
|
|
|
|
packKey: state.selectedPackKey,
|
|
|
|
installPlatform: !!state.client.installPlatform
|
|
|
|
installPlatform: !!state.client.installPlatform,
|
|
|
|
|
|
|
|
// 참가자는 친구 서버에 접속만 하므로 클라이언트에 맵을 풀지 않는다.
|
|
|
|
|
|
|
|
skipMap: state.mode === 'multi' && state.role === 'participant'
|
|
|
|
})
|
|
|
|
})
|
|
|
|
msg.textContent = tt('step4.sub42.done')
|
|
|
|
msg.textContent = tt('step4.sub42.done')
|
|
|
|
msg.classList.add('success')
|
|
|
|
msg.classList.add('success')
|
|
|
|
@@ -683,11 +687,13 @@ function renderStep5() {
|
|
|
|
clearPage()
|
|
|
|
clearPage()
|
|
|
|
var section = document.createElement('section')
|
|
|
|
var section = document.createElement('section')
|
|
|
|
section.className = 'page'
|
|
|
|
section.className = 'page'
|
|
|
|
var multi = state.mode === 'multi'
|
|
|
|
// 서버 마무리 액션 (바로가기/서버 실행) 은 step3 를 거친 호스트 만 노출한다.
|
|
|
|
|
|
|
|
// 싱글, 멀티+참가자 는 서버를 직접 띄우지 않으므로 런처만 보여준다.
|
|
|
|
|
|
|
|
var showServerActions = state.mode === 'multi' && state.role === 'host'
|
|
|
|
section.innerHTML =
|
|
|
|
section.innerHTML =
|
|
|
|
'<h2>' + tt('step5.heading') + '</h2>' +
|
|
|
|
'<h2>' + tt('step5.heading') + '</h2>' +
|
|
|
|
'<p>' + tt('step5.summary') + '</p>' +
|
|
|
|
'<p>' + tt('step5.summary') + '</p>' +
|
|
|
|
(multi ? '<div class="subStep">' +
|
|
|
|
(showServerActions ? '<div class="subStep">' +
|
|
|
|
'<h3>' + tt('step5.serverHeading') + '</h3>' +
|
|
|
|
'<h3>' + tt('step5.serverHeading') + '</h3>' +
|
|
|
|
'<button class="secondaryBtn" id="openFolder">' + tt('step5.openServerFolder') + '</button>' +
|
|
|
|
'<button class="secondaryBtn" id="openFolder">' + tt('step5.openServerFolder') + '</button>' +
|
|
|
|
'<label class="toggleRow"><input type="checkbox" id="shortcut" checked /> ' + tt('step5.shortcut') + '</label>' +
|
|
|
|
'<label class="toggleRow"><input type="checkbox" id="shortcut" checked /> ' + tt('step5.shortcut') + '</label>' +
|
|
|
|
@@ -700,7 +706,7 @@ function renderStep5() {
|
|
|
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="finish">' + tt('step5.finish') + '</button></div>'
|
|
|
|
'<div class="actionRow"><button class="secondaryBtn" id="back">' + tt('common.back') + '</button><button class="primaryBtn" id="finish">' + tt('step5.finish') + '</button></div>'
|
|
|
|
pageHost.appendChild(section)
|
|
|
|
pageHost.appendChild(section)
|
|
|
|
section.querySelector('#back').addEventListener('click', renderStep4)
|
|
|
|
section.querySelector('#back').addEventListener('click', renderStep4)
|
|
|
|
if (multi) {
|
|
|
|
if (showServerActions) {
|
|
|
|
section.querySelector('#openFolder').addEventListener('click', function () {
|
|
|
|
section.querySelector('#openFolder').addEventListener('click', function () {
|
|
|
|
installerApi.openServerFolder()
|
|
|
|
installerApi.openServerFolder()
|
|
|
|
})
|
|
|
|
})
|
|
|
|
@@ -710,7 +716,7 @@ function renderStep5() {
|
|
|
|
finishBtn.disabled = true
|
|
|
|
finishBtn.disabled = true
|
|
|
|
finishBtn.textContent = tt('step5.finishing')
|
|
|
|
finishBtn.textContent = tt('step5.finishing')
|
|
|
|
try {
|
|
|
|
try {
|
|
|
|
if (multi) {
|
|
|
|
if (showServerActions) {
|
|
|
|
if (section.querySelector('#shortcut').checked) await installerApi.createDesktopShortcut()
|
|
|
|
if (section.querySelector('#shortcut').checked) await installerApi.createDesktopShortcut()
|
|
|
|
if (section.querySelector('#startServer').checked) await installerApi.startServer()
|
|
|
|
if (section.querySelector('#startServer').checked) await installerApi.startServer()
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|