Files
minecraft_launcher/installer/renderer.js

199 lines
6.3 KiB
JavaScript

const state = {
manifestUrl: '',
selectedPack: null,
installPath: '',
jdkPath: ''
}
const panelMap = new Map([...document.querySelectorAll('.panel')].map((panel) => [panel.dataset.panel, panel]))
const stepMap = new Map([...document.querySelectorAll('.steps li')].map((step) => [step.dataset.step, step]))
const logView = document.getElementById('logView')
const packList = document.getElementById('packList')
function setActiveStep(step) {
for (const [key, panel] of panelMap.entries()) {
panel.classList.toggle('active', key === String(step))
}
for (const [key, item] of stepMap.entries()) {
item.classList.toggle('active', key === String(step))
}
}
function appendLog(entry) {
if (entry?.action === 'eula-required') {
document.getElementById('eulaBlock').classList.remove('hidden')
return
}
const line = `[${entry?.tone ?? 'info'}] ${entry?.message ?? ''}`
logView.textContent += `${line}\n`
logView.scrollTop = logView.scrollHeight
}
function validateInstallPath(pathValue) {
const warning = document.getElementById('installPathWarning')
const hasHangul = /[ㄱ-ㅎ|ㅏ-ㅣ|가-힣]/.test(pathValue)
warning.textContent = hasHangul ? '경로에 한글이 포함되면 안 됩니다.' : ''
return !hasHangul && pathValue.trim().length > 0
}
function renderPackList(packs) {
packList.innerHTML = ''
packs.forEach((pack) => {
const label = document.createElement('label')
label.className = 'packOption'
label.innerHTML = `
<input type="radio" name="packChoice" value="${pack.file}" />
<div>
<strong>${pack.name}</strong>
<span>${pack.file}</span>
</div>
`
packList.appendChild(label)
})
packList.addEventListener('change', () => {
const checked = packList.querySelector('input[name="packChoice"]:checked')
if (checked == null) {
state.selectedPack = null
return
}
state.selectedPack = packs.find((pack) => pack.file === checked.value) ?? null
})
}
async function bootstrap() {
const defaults = await window.installerApi.getDefaults()
state.manifestUrl = defaults.manifestUrl
document.getElementById('manifestUrl').value = defaults.manifestUrl
}
window.installerApi.onLog(appendLog)
document.querySelectorAll('[data-back]').forEach((button) => {
button.addEventListener('click', () => {
setActiveStep(button.dataset.back)
})
})
document.getElementById('loadPacksButton').addEventListener('click', async () => {
state.manifestUrl = document.getElementById('manifestUrl').value.trim()
const manifest = await window.installerApi.loadPacks(state.manifestUrl)
renderPackList(manifest.packs)
})
document.getElementById('toStep2').addEventListener('click', () => {
if (state.selectedPack == null) {
alert('서버팩을 먼저 선택하세요.')
return
}
setActiveStep(2)
})
document.getElementById('browseInstallPath').addEventListener('click', async () => {
const selected = await window.installerApi.chooseDirectory()
if (selected != null) {
state.installPath = selected
document.getElementById('installPath').value = selected
validateInstallPath(selected)
}
})
document.getElementById('installPath').addEventListener('input', (event) => {
state.installPath = event.target.value
validateInstallPath(state.installPath)
})
document.getElementById('toStep3').addEventListener('click', () => {
if (!validateInstallPath(state.installPath)) {
alert('올바른 설치 경로를 입력하세요.')
return
}
setActiveStep(3)
})
document.getElementById('detectJdkButton').addEventListener('click', async () => {
const result = await window.installerApi.detectJdk()
document.getElementById('jdkStatus').textContent = result.detected != null
? `자동 탐색 성공: ${result.detected}`
: `JDK를 찾지 못했습니다. 탐색 경로: ${result.candidates.join(', ') || '없음'}`
if (result.detected != null) {
state.jdkPath = result.detected
document.getElementById('jdkPath').value = result.detected
}
})
document.getElementById('browseJdkPath').addEventListener('click', async () => {
const selected = await window.installerApi.chooseJdk()
if (selected != null) {
state.jdkPath = selected
document.getElementById('jdkPath').value = selected
}
})
document.getElementById('jdkPath').addEventListener('input', (event) => {
state.jdkPath = event.target.value
})
document.getElementById('toStep4').addEventListener('click', () => {
if (state.jdkPath.trim().length === 0) {
alert('JDK 경로를 지정하세요.')
return
}
setActiveStep(4)
})
document.getElementById('startInstallButton').addEventListener('click', async () => {
logView.textContent = ''
document.getElementById('eulaBlock').classList.add('hidden')
const result = await window.installerApi.startInstall({
manifestUrl: state.manifestUrl,
packFile: state.selectedPack.file,
installPath: state.installPath,
jdkPath: state.jdkPath
})
if (result.warning != null) {
appendLog({ message: result.warning, tone: 'warn' })
}
setActiveStep(result.nextStep)
})
document.getElementById('acceptEulaButton').addEventListener('click', async () => {
document.getElementById('eulaBlock').classList.add('hidden')
await window.installerApi.acceptEula()
})
document.getElementById('openConfigEditorButton').addEventListener('click', async () => {
const url = await window.installerApi.openConfigEditor()
document.getElementById('configEditorStatus').textContent = `브라우저에서 열림: ${url}`
})
document.getElementById('toStep6').addEventListener('click', () => {
setActiveStep(6)
})
document.getElementById('configurePortButton').addEventListener('click', async () => {
const result = await window.installerApi.configurePort()
document.getElementById('portStatusBox').textContent = result.message
})
document.getElementById('toStep7').addEventListener('click', () => {
setActiveStep(7)
})
document.getElementById('openFolderButton').addEventListener('click', async () => {
await window.installerApi.openFolder()
})
document.getElementById('finishButton').addEventListener('click', async () => {
const createShortcut = document.getElementById('createShortcutToggle').checked
const runServer = document.getElementById('runServerToggle').checked
await window.installerApi.createShortcut(createShortcut)
await window.installerApi.runServer(runServer)
alert('설치가 완료되었습니다.')
})
bootstrap()