minigame 4 colour question
This commit is contained in:
+246
-7
@@ -352,8 +352,194 @@
|
||||
});
|
||||
}
|
||||
|
||||
function loadQuizCarryPanel() {
|
||||
gameQuizFetch('GET').then(function (data) {
|
||||
/** ค่าเริ่มต้น RGBA สำหรับแผงคำถามบนแผนที่ (quiz_carry) */
|
||||
var QUIZ_CARRY_THEME_DEFAULTS = {
|
||||
bg: { r: 12, g: 14, b: 28, a: 0.88 },
|
||||
border: { r: 255, g: 214, b: 102, a: 0.7 },
|
||||
text: { r: 241, g: 245, b: 249, a: 1 },
|
||||
};
|
||||
|
||||
function quizCarryClampByte(n) {
|
||||
return Math.max(0, Math.min(255, Math.round(Number(n)) || 0));
|
||||
}
|
||||
|
||||
function quizCarryHexFromRgb(r, g, b) {
|
||||
return '#' + [r, g, b].map(function (x) {
|
||||
var h = quizCarryClampByte(x).toString(16);
|
||||
return h.length === 1 ? '0' + h : h;
|
||||
}).join('');
|
||||
}
|
||||
|
||||
function quizCarryParseHexToRgb(hex) {
|
||||
var h = String(hex || '').trim().replace(/^#/, '');
|
||||
if (!h) return null;
|
||||
if (h.length === 3) {
|
||||
return {
|
||||
r: parseInt(h[0] + h[0], 16),
|
||||
g: parseInt(h[1] + h[1], 16),
|
||||
b: parseInt(h[2] + h[2], 16),
|
||||
alpha01: null,
|
||||
};
|
||||
}
|
||||
if (h.length === 6) {
|
||||
return {
|
||||
r: parseInt(h.slice(0, 2), 16),
|
||||
g: parseInt(h.slice(2, 4), 16),
|
||||
b: parseInt(h.slice(4, 6), 16),
|
||||
alpha01: null,
|
||||
};
|
||||
}
|
||||
if (h.length === 8) {
|
||||
return {
|
||||
r: parseInt(h.slice(0, 2), 16),
|
||||
g: parseInt(h.slice(2, 4), 16),
|
||||
b: parseInt(h.slice(4, 6), 16),
|
||||
alpha01: parseInt(h.slice(6, 8), 16) / 255,
|
||||
};
|
||||
}
|
||||
return null;
|
||||
}
|
||||
|
||||
function quizCarryParseCssColor(str, fallback) {
|
||||
var s = String(str == null ? '' : str).trim();
|
||||
if (!s) return fallback;
|
||||
var m = /^rgba?\(\s*([0-9]+)\s*,\s*([0-9]+)\s*,\s*([0-9]+)\s*(?:,\s*([0-9.]+)\s*)?\)$/i.exec(s);
|
||||
if (m) {
|
||||
var a = m[4] != null && m[4] !== '' ? parseFloat(m[4]) : 1;
|
||||
if (!Number.isFinite(a)) a = 1;
|
||||
return {
|
||||
r: quizCarryClampByte(parseInt(m[1], 10)),
|
||||
g: quizCarryClampByte(parseInt(m[2], 10)),
|
||||
b: quizCarryClampByte(parseInt(m[3], 10)),
|
||||
a: Math.max(0, Math.min(1, a)),
|
||||
};
|
||||
}
|
||||
if (/^#/.test(s)) {
|
||||
var pr = quizCarryParseHexToRgb(s);
|
||||
if (!pr) return fallback;
|
||||
var a = pr.alpha01 != null ? pr.alpha01 : 1;
|
||||
return { r: pr.r, g: pr.g, b: pr.b, a: Math.max(0, Math.min(1, a)) };
|
||||
}
|
||||
return fallback;
|
||||
}
|
||||
|
||||
function quizCarryRgbToRgbaString(o) {
|
||||
var a = Math.max(0, Math.min(1, Number(o.a)));
|
||||
var t = Math.round(a * 1000) / 1000;
|
||||
return 'rgba(' + quizCarryClampByte(o.r) + ', ' + quizCarryClampByte(o.g) + ', ' + quizCarryClampByte(o.b) + ', ' + t + ')';
|
||||
}
|
||||
|
||||
function quizCarryRowPrefix(kind) {
|
||||
return 'quiz-carry-theme-' + kind;
|
||||
}
|
||||
|
||||
function quizCarryThemeHiddenId(kind) {
|
||||
if (kind === 'bg') return 'quiz-carry-theme-bg';
|
||||
if (kind === 'border') return 'quiz-carry-theme-border';
|
||||
return 'quiz-carry-theme-text';
|
||||
}
|
||||
|
||||
function quizCarrySetPickersFromColorString(kind, cssStr) {
|
||||
var fb = QUIZ_CARRY_THEME_DEFAULTS[kind];
|
||||
var o = quizCarryParseCssColor(cssStr, fb);
|
||||
var pref = quizCarryRowPrefix(kind);
|
||||
var sw = el(pref + '-swatch');
|
||||
var ra = el(pref + '-alpha');
|
||||
var out = el(pref + '-alpha-out');
|
||||
var hi = el(quizCarryThemeHiddenId(kind));
|
||||
var pr = el(pref + '-preview');
|
||||
if (!sw || !ra || !hi) return;
|
||||
sw.value = quizCarryHexFromRgb(o.r, o.g, o.b);
|
||||
var pct = Math.max(0, Math.min(100, Math.round(Number(o.a) * 100)));
|
||||
ra.value = String(pct);
|
||||
if (out) out.textContent = pct + '%';
|
||||
hi.value = quizCarryRgbToRgbaString(o);
|
||||
if (pr) pr.textContent = hi.value;
|
||||
}
|
||||
|
||||
function quizCarryComposeFromPickers(kind) {
|
||||
var pref = quizCarryRowPrefix(kind);
|
||||
var sw = el(pref + '-swatch');
|
||||
var ra = el(pref + '-alpha');
|
||||
if (!sw || !ra) return '';
|
||||
var pr = quizCarryParseHexToRgb(sw.value);
|
||||
if (!pr) return '';
|
||||
var pct = parseInt(String(ra.value), 10);
|
||||
if (!Number.isFinite(pct)) pct = 100;
|
||||
pct = Math.max(0, Math.min(100, pct));
|
||||
return quizCarryRgbToRgbaString({ r: pr.r, g: pr.g, b: pr.b, a: pct / 100 });
|
||||
}
|
||||
|
||||
function quizCarrySyncRowOutput(kind) {
|
||||
var s = quizCarryComposeFromPickers(kind);
|
||||
var hi = el(quizCarryThemeHiddenId(kind));
|
||||
var pref = quizCarryRowPrefix(kind);
|
||||
var ra = el(pref + '-alpha');
|
||||
var out = el(pref + '-alpha-out');
|
||||
var pr = el(pref + '-preview');
|
||||
if (hi) hi.value = s;
|
||||
if (out && ra) out.textContent = String(Math.max(0, Math.min(100, parseInt(ra.value, 10) || 0))) + '%';
|
||||
if (pr && hi) pr.textContent = hi.value;
|
||||
}
|
||||
|
||||
/** อ่านค่าจาก color + range โดยตรง (ไม่พึ่ง hidden ที่อาจว่าง) ก่อน PUT */
|
||||
function quizCarryBuildThemeForSave() {
|
||||
quizCarryBindThemePickersOnce();
|
||||
['bg', 'border', 'text'].forEach(function (k) {
|
||||
quizCarrySyncRowOutput(k);
|
||||
});
|
||||
var fbBg = QUIZ_CARRY_THEME_DEFAULTS.bg;
|
||||
var fbBr = QUIZ_CARRY_THEME_DEFAULTS.border;
|
||||
var fbTx = QUIZ_CARRY_THEME_DEFAULTS.text;
|
||||
var sBg = quizCarryComposeFromPickers('bg');
|
||||
var sBr = quizCarryComposeFromPickers('border');
|
||||
var sTx = quizCarryComposeFromPickers('text');
|
||||
var bwEl = el('quiz-carry-theme-border-w');
|
||||
var bw = bwEl ? parseInt(String(bwEl.value || '2'), 10) : 2;
|
||||
if (!Number.isFinite(bw)) bw = 2;
|
||||
bw = Math.max(0, Math.min(12, Math.round(bw)));
|
||||
return {
|
||||
panelBg: (sBg && sBg.trim()) ? sBg.trim().slice(0, 120) : quizCarryRgbToRgbaString(fbBg),
|
||||
panelBorder: (sBr && sBr.trim()) ? sBr.trim().slice(0, 120) : quizCarryRgbToRgbaString(fbBr),
|
||||
textColor: (sTx && sTx.trim()) ? sTx.trim().slice(0, 120) : quizCarryRgbToRgbaString(fbTx),
|
||||
borderWidthPx: bw,
|
||||
};
|
||||
}
|
||||
|
||||
function quizCarryBindThemePickersOnce() {
|
||||
if (quizCarryBindThemePickersOnce._done) return;
|
||||
['bg', 'border', 'text'].forEach(function (kind) {
|
||||
var pref = quizCarryRowPrefix(kind);
|
||||
var sw = el(pref + '-swatch');
|
||||
var ra = el(pref + '-alpha');
|
||||
if (!sw || !ra) return;
|
||||
if (ra.getAttribute('data-bound') === '1') return;
|
||||
ra.setAttribute('data-bound', '1');
|
||||
function sync() {
|
||||
quizCarrySyncRowOutput(kind);
|
||||
}
|
||||
sw.addEventListener('input', sync);
|
||||
sw.addEventListener('change', sync);
|
||||
ra.addEventListener('input', sync);
|
||||
ra.addEventListener('change', sync);
|
||||
});
|
||||
quizCarryBindThemePickersOnce._done = true;
|
||||
}
|
||||
|
||||
function loadQuizCarryPanel(opts) {
|
||||
opts = opts || {};
|
||||
var delay = Number(opts.fetchDelayMs) || 0;
|
||||
var runLoad = function () {
|
||||
gameQuizFetch('GET').then(function (data) {
|
||||
if (opts.themeOverride && typeof opts.themeOverride === 'object') {
|
||||
data.carryMapPanelTheme = opts.themeOverride;
|
||||
}
|
||||
if (opts.timingOverride && typeof opts.timingOverride === 'object') {
|
||||
var t = opts.timingOverride;
|
||||
if (t.carryReadMs != null) data.carryReadMs = t.carryReadMs;
|
||||
if (t.carryAnswerMs != null) data.carryAnswerMs = t.carryAnswerMs;
|
||||
if (t.carrySessionLength != null) data.carrySessionLength = t.carrySessionLength;
|
||||
}
|
||||
renderQuizCarryAdminList(data.carryQuestions || []);
|
||||
var readSec = el('quiz-carry-read-sec');
|
||||
var ansSec = el('quiz-carry-answer-sec');
|
||||
@@ -370,10 +556,23 @@
|
||||
var sl = parseInt(String(data.carrySessionLength), 10);
|
||||
sessLen.value = String(Number.isFinite(sl) && sl >= 0 ? sl : 0);
|
||||
}
|
||||
setMsg('quiz-carry-settings-msg', '', '');
|
||||
quizCarryBindThemePickersOnce();
|
||||
var th = data.carryMapPanelTheme && typeof data.carryMapPanelTheme === 'object' ? data.carryMapPanelTheme : {};
|
||||
quizCarrySetPickersFromColorString('bg', th.panelBg);
|
||||
quizCarrySetPickersFromColorString('border', th.panelBorder);
|
||||
quizCarrySetPickersFromColorString('text', th.textColor);
|
||||
var bwInp = el('quiz-carry-theme-border-w');
|
||||
if (bwInp) {
|
||||
var bw = parseInt(String(th.borderWidthPx), 10);
|
||||
bwInp.value = String(Number.isFinite(bw) && bw >= 0 ? Math.min(12, bw) : 2);
|
||||
}
|
||||
if (opts.clearMsg !== false) setMsg('quiz-carry-settings-msg', '', '');
|
||||
}).catch(function (e) {
|
||||
setMsg('quiz-carry-settings-msg', e.message || 'โหลดไม่ได้', 'error');
|
||||
});
|
||||
};
|
||||
if (delay > 0) setTimeout(runLoad, delay);
|
||||
else runLoad();
|
||||
}
|
||||
|
||||
function saveQuizCarryPanel() {
|
||||
@@ -426,13 +625,52 @@
|
||||
if (!Number.isFinite(carrySessionLength) || carrySessionLength < 0) carrySessionLength = 0;
|
||||
if (carrySessionLength > 500) carrySessionLength = 500;
|
||||
|
||||
gameQuizFetch('PUT', {
|
||||
carryQuestions: carryQuestions,
|
||||
var carryMapPanelTheme = quizCarryBuildThemeForSave();
|
||||
|
||||
var blockEls = list.querySelectorAll('.quiz-carry-admin-block');
|
||||
var hasAnyQuestionText = false;
|
||||
for (var bi = 0; bi < blockEls.length; bi++) {
|
||||
var qn = blockEls[bi].querySelector('.quiz-carry-q-text');
|
||||
if (qn && String(qn.value || '').trim()) {
|
||||
hasAnyQuestionText = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (carryQuestions.length === 0 && hasAnyQuestionText) {
|
||||
setMsg(
|
||||
'quiz-carry-settings-msg',
|
||||
'ยังบันทึกชุดคำถามไม่ได้: แต่ละข้อต้องมีคำถาม ตัวเลือกอย่างน้อย 2 ช่องที่กรอกแล้ว และเลือก «ข้อที่ถูกต้อง» — ตรวจแถวที่มีข้อความค้าง',
|
||||
'error',
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
var putBody = {
|
||||
carryReadMs: carryReadMs,
|
||||
carryAnswerMs: carryAnswerMs,
|
||||
carrySessionLength: carrySessionLength,
|
||||
}).then(function () {
|
||||
setMsg('quiz-carry-settings-msg', 'บันทึกแล้ว', 'ok');
|
||||
carryMapPanelTheme: carryMapPanelTheme,
|
||||
};
|
||||
if (carryQuestions.length > 0) {
|
||||
putBody.carryQuestions = carryQuestions;
|
||||
}
|
||||
|
||||
gameQuizFetch('PUT', putBody).then(function (res) {
|
||||
var tail = carryQuestions.length ? ' · คำถาม ' + carryQuestions.length + ' ข้อ' : ' · คงชุดคำถามเดิม (อัปเดตเวลา/ธีมอย่างเดียว)';
|
||||
var themeFromRes = res && res.carryMapPanelTheme && typeof res.carryMapPanelTheme === 'object' ? res.carryMapPanelTheme : null;
|
||||
var themeOk = !!themeFromRes;
|
||||
var themeTail = themeOk ? ' · ธีมแผงบันทึกแล้ว' : '';
|
||||
setMsg('quiz-carry-settings-msg', 'บันทึกแล้ว' + tail + themeTail, 'ok');
|
||||
loadQuizCarryPanel({
|
||||
clearMsg: false,
|
||||
themeOverride: themeFromRes || carryMapPanelTheme,
|
||||
timingOverride: {
|
||||
carryReadMs: carryReadMs,
|
||||
carryAnswerMs: carryAnswerMs,
|
||||
carrySessionLength: carrySessionLength,
|
||||
},
|
||||
fetchDelayMs: 120,
|
||||
});
|
||||
}).catch(function (e) {
|
||||
setMsg('quiz-carry-settings-msg', e.message || 'บันทึกไม่ได้', 'error');
|
||||
});
|
||||
@@ -1578,6 +1816,7 @@
|
||||
});
|
||||
}
|
||||
if (btnQuizCarrySave) btnQuizCarrySave.addEventListener('click', saveQuizCarryPanel);
|
||||
quizCarryBindThemePickersOnce();
|
||||
|
||||
var btnQbBattleAdd = el('btn-qb-battle-add');
|
||||
var btnQbBattleSave = el('btn-qb-battle-save');
|
||||
|
||||
Reference in New Issue
Block a user