Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 3f553f958d |
@@ -189,63 +189,57 @@ function showAgreementError(message) {
|
|||||||
section.querySelector('#retry').addEventListener('click', renderAgreement)
|
section.querySelector('#retry').addEventListener('click', renderAgreement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 약관을 한 건씩 페이지로 보여준다. 각 약관마다 "해당 약관에 동의합니다" 체크가 있고,
|
||||||
|
// 끝까지 스크롤해 읽어야 체크할 수 있으며, [다음] 을 누르면 다음 약관 페이지가 화면
|
||||||
|
// 맨 위에서부터 나온다. 마지막 약관까지 동의하면 다음 단계(step2)로 진행한다.
|
||||||
function renderAgreementWithKinds(KINDS) {
|
function renderAgreementWithKinds(KINDS) {
|
||||||
|
var idx = 0
|
||||||
|
var accepted = {} // kind -> true (뒤로 갔다 와도 동의 상태 유지)
|
||||||
|
var cache = {} // kind -> 렌더된 HTML
|
||||||
|
|
||||||
var section = document.createElement('section')
|
var section = document.createElement('section')
|
||||||
section.className = 'page'
|
section.className = 'page'
|
||||||
|
pageHost.appendChild(section)
|
||||||
|
|
||||||
|
function renderCurrent() {
|
||||||
|
var k = KINDS[idx]
|
||||||
|
var isLast = idx === KINDS.length - 1
|
||||||
section.innerHTML =
|
section.innerHTML =
|
||||||
'<h2>' + escapeHtml(tt('agreement.heading')) + '</h2>' +
|
'<h2>' + escapeHtml(tt('agreement.heading')) + '</h2>' +
|
||||||
'<p class="formMessage">' + escapeHtml(tt('agreement.intro')) + '</p>' +
|
'<p class="formMessage">' + escapeHtml(tt('agreement.stepLabel', { current: idx + 1, total: KINDS.length, label: k.tab })) + '</p>' +
|
||||||
'<div class="tabBar" id="agTabs">' +
|
'<div class="agreementBody" id="agBody" style="border-radius:10px;">' + escapeHtml(tt('agreement.loading')) + '</div>' +
|
||||||
KINDS.map(function (k, i) {
|
'<div class="formMessage" id="agHint">' + escapeHtml(tt('agreement.readToBottom')) + '</div>' +
|
||||||
return '<button type="button" class="tabBtn' + (i === 0 ? ' active' : '') + '" data-ag="' + k.id + '">' + escapeHtml(k.tab) + '</button>'
|
'<label class="toggleRow" style="margin-top:8px;"><input type="checkbox" id="agAccept" disabled /> ' +
|
||||||
}).join('') +
|
escapeHtml(tt('agreement.agreeThis')) + '</label>' +
|
||||||
'</div>' +
|
|
||||||
'<div class="agreementBody" id="agBody">' + escapeHtml(tt('agreement.loading')) + '</div>' +
|
|
||||||
'<label class="toggleRow" style="margin-top:12px;"><input type="checkbox" id="agAccept" /> ' +
|
|
||||||
escapeHtml(tt('agreement.agreeAll')) + '</label>' +
|
|
||||||
'<div class="formMessage" id="agMsg"></div>' +
|
'<div class="formMessage" id="agMsg"></div>' +
|
||||||
'<div class="actionRow">' +
|
'<div class="actionRow">' +
|
||||||
' <button class="secondaryBtn" id="back">' + escapeHtml(tt('common.back')) + '</button>' +
|
' <button class="secondaryBtn" id="back">' + escapeHtml(tt('common.back')) + '</button>' +
|
||||||
' <button class="primaryBtn" id="next" disabled>' + escapeHtml(tt('common.next')) + '</button>' +
|
' <button class="primaryBtn" id="next" disabled>' + escapeHtml(tt('common.next')) + '</button>' +
|
||||||
'</div>'
|
'</div>'
|
||||||
pageHost.appendChild(section)
|
|
||||||
|
|
||||||
var body = section.querySelector('#agBody')
|
var body = section.querySelector('#agBody')
|
||||||
var tabs = section.querySelectorAll('[data-ag]')
|
|
||||||
var nextBtn = section.querySelector('#next')
|
|
||||||
var accept = section.querySelector('#agAccept')
|
var accept = section.querySelector('#agAccept')
|
||||||
|
var nextBtn = section.querySelector('#next')
|
||||||
var msg = section.querySelector('#agMsg')
|
var msg = section.querySelector('#agMsg')
|
||||||
|
var hint = section.querySelector('#agHint')
|
||||||
|
|
||||||
// 본문 캐시. 탭 전환 시 재요청하지 않음.
|
// 새 약관 페이지는 화면 맨 위에서부터 보이도록 스크롤을 올린다.
|
||||||
var cache = {}
|
if (pageHost) pageHost.scrollTop = 0
|
||||||
|
|
||||||
function showKind(kind) {
|
function markReadable() {
|
||||||
if (cache[kind]) { body.innerHTML = cache[kind]; return }
|
if (!accept.disabled) return
|
||||||
body.textContent = tt('agreement.loading')
|
accept.disabled = false
|
||||||
api.getTerm(kind).then(function (res) {
|
hint.textContent = ''
|
||||||
if (!res.ok) {
|
|
||||||
body.innerHTML = '<p class="formMessage error">' + escapeHtml(tt('agreement.loadFailed', { message: res.message || '' })) + '</p>'
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var html = renderTermsMarkdown(res.content || '')
|
function checkScrolled() {
|
||||||
cache[kind] = html
|
if (body.scrollHeight - body.scrollTop - body.clientHeight <= 6) markReadable()
|
||||||
body.innerHTML = html
|
|
||||||
}).catch(function (err) {
|
|
||||||
body.innerHTML = '<p class="formMessage error">' + escapeHtml(tt('agreement.loadFailed', { message: err.message })) + '</p>'
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
body.addEventListener('scroll', checkScrolled)
|
||||||
tabs.forEach(function (b) {
|
|
||||||
b.addEventListener('click', function () {
|
|
||||||
tabs.forEach(function (x) { x.classList.remove('active') })
|
|
||||||
b.classList.add('active')
|
|
||||||
showKind(b.getAttribute('data-ag'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
accept.addEventListener('change', function () {
|
accept.addEventListener('change', function () {
|
||||||
|
accepted[k.id] = accept.checked
|
||||||
nextBtn.disabled = !accept.checked
|
nextBtn.disabled = !accept.checked
|
||||||
if (accept.checked) msg.textContent = ''
|
if (accept.checked) { msg.textContent = ''; msg.classList.remove('error') }
|
||||||
})
|
})
|
||||||
|
|
||||||
nextBtn.addEventListener('click', function () {
|
nextBtn.addEventListener('click', function () {
|
||||||
@@ -254,11 +248,51 @@ function renderAgreementWithKinds(KINDS) {
|
|||||||
msg.classList.add('error')
|
msg.classList.add('error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
renderStep2()
|
if (isLast) renderStep2()
|
||||||
|
else { idx++; renderCurrent() }
|
||||||
|
})
|
||||||
|
section.querySelector('#back').addEventListener('click', function () {
|
||||||
|
if (idx === 0) renderStep1()
|
||||||
|
else { idx--; renderCurrent() }
|
||||||
})
|
})
|
||||||
section.querySelector('#back').addEventListener('click', renderStep1)
|
|
||||||
|
|
||||||
showKind(KINDS[0].id)
|
function afterLoad() {
|
||||||
|
body.scrollTop = 0
|
||||||
|
if (accepted[k.id]) {
|
||||||
|
accept.disabled = false
|
||||||
|
accept.checked = true
|
||||||
|
nextBtn.disabled = false
|
||||||
|
hint.textContent = ''
|
||||||
|
}
|
||||||
|
setTimeout(function () {
|
||||||
|
if (body.scrollHeight - body.clientHeight <= 6) markReadable()
|
||||||
|
else checkScrolled()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache[k.id]) {
|
||||||
|
body.innerHTML = cache[k.id]
|
||||||
|
afterLoad()
|
||||||
|
} else {
|
||||||
|
body.textContent = tt('agreement.loading')
|
||||||
|
api.getTerm(k.id).then(function (res) {
|
||||||
|
if (!res.ok) {
|
||||||
|
body.innerHTML = '<p class="formMessage error">' + escapeHtml(tt('agreement.loadFailed', { message: res.message || '' })) + '</p>'
|
||||||
|
markReadable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var html = renderTermsMarkdown(res.content || '')
|
||||||
|
cache[k.id] = html
|
||||||
|
body.innerHTML = html
|
||||||
|
afterLoad()
|
||||||
|
}).catch(function (err) {
|
||||||
|
body.innerHTML = '<p class="formMessage error">' + escapeHtml(tt('agreement.loadFailed', { message: err.message })) + '</p>'
|
||||||
|
markReadable()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCurrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 인스톨러용 미니 markdown 렌더러. 사이트 termsEditor 와 같은 규칙을 처리한다.
|
// 인스톨러용 미니 markdown 렌더러. 사이트 termsEditor 와 같은 규칙을 처리한다.
|
||||||
|
|||||||
@@ -232,63 +232,55 @@ function showAgreementError(message) {
|
|||||||
section.querySelector('#retry').addEventListener('click', renderAgreement)
|
section.querySelector('#retry').addEventListener('click', renderAgreement)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// 약관을 한 건씩 페이지로 보여준다. 각 약관마다 "해당 약관에 동의합니다" 체크가 있고,
|
||||||
|
// 끝까지 스크롤해 읽어야 체크할 수 있으며, [다음] 을 누르면 다음 약관 페이지가 화면
|
||||||
|
// 맨 위에서부터 나온다. 마지막 약관까지 동의하면 다음 단계(step2)로 진행한다.
|
||||||
function renderAgreementWithKinds(KINDS) {
|
function renderAgreementWithKinds(KINDS) {
|
||||||
|
var idx = 0
|
||||||
|
var accepted = {} // kind -> true (뒤로 갔다 와도 동의 상태 유지)
|
||||||
|
var cache = {} // kind -> 렌더된 HTML
|
||||||
|
|
||||||
var section = document.createElement('section')
|
var section = document.createElement('section')
|
||||||
section.className = 'page'
|
section.className = 'page'
|
||||||
section.innerHTML =
|
|
||||||
'<h2>' + tt('agreement.heading') + '</h2>' +
|
|
||||||
'<p class="formMessage">' + tt('agreement.intro') + '</p>' +
|
|
||||||
'<div class="tabBar" id="agTabs">' +
|
|
||||||
KINDS.map(function (k, i) {
|
|
||||||
return '<button type="button" class="tabBtn' + (i === 0 ? ' active' : '') + '" data-ag="' + escapeHtml(k.id) + '">' + escapeHtml(k.tab) + '</button>'
|
|
||||||
}).join('') +
|
|
||||||
'</div>' +
|
|
||||||
'<div class="agreementBody" id="agBody">' + tt('agreement.loading') + '</div>' +
|
|
||||||
'<label class="toggleRow" style="margin-top:12px;"><input type="checkbox" id="agAccept" /> ' +
|
|
||||||
tt('agreement.agreeAll') + '</label>' +
|
|
||||||
'<div class="formMessage" id="agMsg"></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)
|
||||||
|
|
||||||
|
function renderCurrent() {
|
||||||
|
var k = KINDS[idx]
|
||||||
|
var isLast = idx === KINDS.length - 1
|
||||||
|
section.innerHTML =
|
||||||
|
'<h2>' + tt('agreement.heading') + '</h2>' +
|
||||||
|
'<p class="formMessage">' + escapeHtml(tt('agreement.stepLabel', { current: idx + 1, total: KINDS.length, label: k.tab })) + '</p>' +
|
||||||
|
'<div class="agreementBody" id="agBody" style="border-radius:10px;">' + tt('agreement.loading') + '</div>' +
|
||||||
|
'<div class="formMessage" id="agHint">' + tt('agreement.readToBottom') + '</div>' +
|
||||||
|
'<label class="toggleRow" style="margin-top:8px;"><input type="checkbox" id="agAccept" disabled /> ' +
|
||||||
|
tt('agreement.agreeThis') + '</label>' +
|
||||||
|
'<div class="formMessage" id="agMsg"></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 body = section.querySelector('#agBody')
|
var body = section.querySelector('#agBody')
|
||||||
var tabs = section.querySelectorAll('[data-ag]')
|
|
||||||
var nextBtn = section.querySelector('#next')
|
|
||||||
var accept = section.querySelector('#agAccept')
|
var accept = section.querySelector('#agAccept')
|
||||||
|
var nextBtn = section.querySelector('#next')
|
||||||
var msg = section.querySelector('#agMsg')
|
var msg = section.querySelector('#agMsg')
|
||||||
|
var hint = section.querySelector('#agHint')
|
||||||
|
|
||||||
// 약관 본문은 한 번 받으면 캐시. 탭 전환 시 재요청하지 않는다.
|
// 새 약관 페이지는 화면 맨 위에서부터 보이도록 스크롤을 올린다.
|
||||||
var cache = {}
|
if (pageHost) pageHost.scrollTop = 0
|
||||||
|
|
||||||
function showKind(kind) {
|
function markReadable() {
|
||||||
if (cache[kind]) {
|
if (!accept.disabled) return
|
||||||
body.innerHTML = cache[kind]
|
accept.disabled = false
|
||||||
return
|
hint.textContent = ''
|
||||||
}
|
}
|
||||||
body.textContent = tt('agreement.loading')
|
function checkScrolled() {
|
||||||
installerApi.getTerm(kind).then(function (res) {
|
// 본문을 끝까지(하단 근처) 내렸으면 동의 체크를 허용한다.
|
||||||
if (!res.ok) {
|
if (body.scrollHeight - body.scrollTop - body.clientHeight <= 6) markReadable()
|
||||||
body.innerHTML = '<p class="formMessage error">' + tt('agreement.loadFailed', { message: res.message || '' }) + '</p>'
|
|
||||||
return
|
|
||||||
}
|
}
|
||||||
var html = renderTermsMarkdown(res.content || '')
|
body.addEventListener('scroll', checkScrolled)
|
||||||
cache[kind] = html
|
|
||||||
body.innerHTML = html
|
|
||||||
}).catch(function (err) {
|
|
||||||
body.innerHTML = '<p class="formMessage error">' + tt('agreement.loadFailed', { message: err.message }) + '</p>'
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
tabs.forEach(function (b) {
|
|
||||||
b.addEventListener('click', function () {
|
|
||||||
tabs.forEach(function (x) { x.classList.remove('active') })
|
|
||||||
b.classList.add('active')
|
|
||||||
showKind(b.getAttribute('data-ag'))
|
|
||||||
})
|
|
||||||
})
|
|
||||||
|
|
||||||
accept.addEventListener('change', function () {
|
accept.addEventListener('change', function () {
|
||||||
|
accepted[k.id] = accept.checked
|
||||||
nextBtn.disabled = !accept.checked
|
nextBtn.disabled = !accept.checked
|
||||||
if (accept.checked) msg.textContent = ''
|
if (accept.checked) { msg.textContent = ''; msg.classList.remove('error') }
|
||||||
})
|
})
|
||||||
|
|
||||||
nextBtn.addEventListener('click', function () {
|
nextBtn.addEventListener('click', function () {
|
||||||
@@ -297,11 +289,53 @@ function renderAgreementWithKinds(KINDS) {
|
|||||||
msg.classList.add('error')
|
msg.classList.add('error')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
renderStep2()
|
if (isLast) renderStep2()
|
||||||
|
else { idx++; renderCurrent() }
|
||||||
|
})
|
||||||
|
section.querySelector('#back').addEventListener('click', function () {
|
||||||
|
if (idx === 0) renderStep1()
|
||||||
|
else { idx--; renderCurrent() }
|
||||||
})
|
})
|
||||||
section.querySelector('#back').addEventListener('click', renderStep1)
|
|
||||||
|
|
||||||
showKind(KINDS[0].id)
|
function afterLoad() {
|
||||||
|
body.scrollTop = 0
|
||||||
|
// 이미 동의했던 약관으로 되돌아온 경우: 체크/다음 활성화 유지.
|
||||||
|
if (accepted[k.id]) {
|
||||||
|
accept.disabled = false
|
||||||
|
accept.checked = true
|
||||||
|
nextBtn.disabled = false
|
||||||
|
hint.textContent = ''
|
||||||
|
}
|
||||||
|
// 레이아웃 확정 후: 스크롤이 필요 없을 만큼 짧은 약관이면 바로 동의 허용.
|
||||||
|
setTimeout(function () {
|
||||||
|
if (body.scrollHeight - body.clientHeight <= 6) markReadable()
|
||||||
|
else checkScrolled()
|
||||||
|
}, 0)
|
||||||
|
}
|
||||||
|
|
||||||
|
if (cache[k.id]) {
|
||||||
|
body.innerHTML = cache[k.id]
|
||||||
|
afterLoad()
|
||||||
|
} else {
|
||||||
|
body.textContent = tt('agreement.loading')
|
||||||
|
installerApi.getTerm(k.id).then(function (res) {
|
||||||
|
if (!res.ok) {
|
||||||
|
body.innerHTML = '<p class="formMessage error">' + tt('agreement.loadFailed', { message: res.message || '' }) + '</p>'
|
||||||
|
markReadable()
|
||||||
|
return
|
||||||
|
}
|
||||||
|
var html = renderTermsMarkdown(res.content || '')
|
||||||
|
cache[k.id] = html
|
||||||
|
body.innerHTML = html
|
||||||
|
afterLoad()
|
||||||
|
}).catch(function (err) {
|
||||||
|
body.innerHTML = '<p class="formMessage error">' + tt('agreement.loadFailed', { message: err.message }) + '</p>'
|
||||||
|
markReadable()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
renderCurrent()
|
||||||
}
|
}
|
||||||
|
|
||||||
// 인스톨러용 미니 markdown 렌더러. 사이트 termsEditor 와 동일한 규칙을 처리한다.
|
// 인스톨러용 미니 markdown 렌더러. 사이트 termsEditor 와 동일한 규칙을 처리한다.
|
||||||
|
|||||||
@@ -33,7 +33,7 @@
|
|||||||
},
|
},
|
||||||
"agreement": {
|
"agreement": {
|
||||||
"heading": "약관 동의",
|
"heading": "약관 동의",
|
||||||
"intro": "리소스팩을 설치하기 전에 아래 약관을 모두 확인하고 동의해 주세요.",
|
"intro": "리소스팩을 설치하기 전에 아래 약관을 한 건씩 끝까지 읽고 동의해 주세요.",
|
||||||
"tabResourcepack": "리소스팩 약관",
|
"tabResourcepack": "리소스팩 약관",
|
||||||
"tabInstaller": "리소스팩 설치기 약관",
|
"tabInstaller": "리소스팩 설치기 약관",
|
||||||
"loading": "약관을 불러오는 중...",
|
"loading": "약관을 불러오는 중...",
|
||||||
@@ -41,6 +41,9 @@
|
|||||||
"listLoadFailed": "약관 표시에 실패하여 설치를 진행할 수 없습니다.\n사유: {{message}}\n네트워크 상태를 확인하고 다시 시도하거나, 처음 단계로 돌아가 주세요.",
|
"listLoadFailed": "약관 표시에 실패하여 설치를 진행할 수 없습니다.\n사유: {{message}}\n네트워크 상태를 확인하고 다시 시도하거나, 처음 단계로 돌아가 주세요.",
|
||||||
"retry": "다시 시도",
|
"retry": "다시 시도",
|
||||||
"agreeAll": "위 모든 약관에 동의합니다.",
|
"agreeAll": "위 모든 약관에 동의합니다.",
|
||||||
|
"agreeThis": "해당 약관에 동의합니다.",
|
||||||
|
"readToBottom": "약관을 끝까지 내려서 확인하면 동의할 수 있습니다.",
|
||||||
|
"stepLabel": "약관 {{current}}/{{total}} — {{label}}",
|
||||||
"agreeRequired": "약관에 동의해야 다음 단계로 진행할 수 있습니다.",
|
"agreeRequired": "약관에 동의해야 다음 단계로 진행할 수 있습니다.",
|
||||||
"cancelling": "취소 중…"
|
"cancelling": "취소 중…"
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -41,7 +41,7 @@
|
|||||||
},
|
},
|
||||||
"agreement": {
|
"agreement": {
|
||||||
"heading": "약관 동의",
|
"heading": "약관 동의",
|
||||||
"intro": "설치 전에 아래 약관을 모두 확인하고 동의해 주세요.",
|
"intro": "설치 전에 아래 약관을 한 건씩 끝까지 읽고 동의해 주세요.",
|
||||||
"tabMap": "맵 약관",
|
"tabMap": "맵 약관",
|
||||||
"tabMod": "모드 약관",
|
"tabMod": "모드 약관",
|
||||||
"tabInstaller": "설치기 약관",
|
"tabInstaller": "설치기 약관",
|
||||||
@@ -50,6 +50,9 @@
|
|||||||
"listLoadFailed": "약관 표시에 실패하여 설치를 진행할 수 없습니다.\n사유: {{message}}\n네트워크 상태를 확인하고 다시 시도하거나, 처음 단계로 돌아가 주세요.",
|
"listLoadFailed": "약관 표시에 실패하여 설치를 진행할 수 없습니다.\n사유: {{message}}\n네트워크 상태를 확인하고 다시 시도하거나, 처음 단계로 돌아가 주세요.",
|
||||||
"retry": "다시 시도",
|
"retry": "다시 시도",
|
||||||
"agreeAll": "위 모든 약관에 동의합니다.",
|
"agreeAll": "위 모든 약관에 동의합니다.",
|
||||||
|
"agreeThis": "해당 약관에 동의합니다.",
|
||||||
|
"readToBottom": "약관을 끝까지 내려서 확인하면 동의할 수 있습니다.",
|
||||||
|
"stepLabel": "약관 {{current}}/{{total}} — {{label}}",
|
||||||
"agreeRequired": "약관에 동의해야 다음 단계로 진행할 수 있습니다."
|
"agreeRequired": "약관에 동의해야 다음 단계로 진행할 수 있습니다."
|
||||||
},
|
},
|
||||||
"step1": {
|
"step1": {
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "minecraft-music-quiz-installer",
|
"name": "minecraft-music-quiz-installer",
|
||||||
"version": "0.4.0",
|
"version": "0.4.1",
|
||||||
"description": "마인크래프트 음악퀴즈 간편설치기 + 관리 사이트",
|
"description": "마인크래프트 음악퀴즈 간편설치기 + 관리 사이트",
|
||||||
"main": "dist/installer/main.js",
|
"main": "dist/installer/main.js",
|
||||||
"scripts": {
|
"scripts": {
|
||||||
|
|||||||
Reference in New Issue
Block a user