163 lines
5.6 KiB
HTML
163 lines
5.6 KiB
HTML
<!doctype html>
|
|
<html lang="en">
|
|
<head>
|
|
<title>Courses - ChessStars</title>
|
|
{{template "head" .}}
|
|
</head>
|
|
<body>
|
|
{{template "nav" .}}
|
|
<main>
|
|
<div class="panel">
|
|
<h2>Publish a course</h2>
|
|
<label>Title<br><input id="c-title" size="40"></label><br><br>
|
|
<label>Description<br><textarea id="c-desc" rows="2" cols="40"></textarea></label><br><br>
|
|
<label>Visibility
|
|
<select id="c-vis">
|
|
<option value="private">private (only you)</option>
|
|
<option value="public">public</option>
|
|
</select>
|
|
</label><br><br>
|
|
<button id="c-create">Create course</button>
|
|
<p class="muted" id="c-msg"></p>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h2>Public courses</h2>
|
|
<div id="public-list"></div>
|
|
</div>
|
|
|
|
<div class="panel">
|
|
<h2>My courses</h2>
|
|
<div id="my-list" class="muted">log in to see your courses</div>
|
|
</div>
|
|
|
|
<div class="panel" id="detail-panel" style="display:none">
|
|
<h2 id="detail-title"></h2>
|
|
<p class="muted" id="detail-meta"></p>
|
|
<h3>Chapters</h3>
|
|
<div id="chapter-list"></div>
|
|
|
|
<div id="add-chapter-box" style="display:none">
|
|
<h3>Add chapter</h3>
|
|
<label>Title<br><input id="ch-title" size="40"></label><br><br>
|
|
<label>Annotation<br><textarea id="ch-annotation" rows="2" cols="40"></textarea></label><br><br>
|
|
<label>Solution note (private)<br><textarea id="ch-solution" rows="2" cols="40"></textarea></label><br><br>
|
|
<button id="ch-add">Add chapter</button>
|
|
</div>
|
|
|
|
<div id="chapter-detail" class="panel" style="display:none"></div>
|
|
</div>
|
|
</main>
|
|
|
|
<script>
|
|
let currentCourseID = null;
|
|
|
|
function courseCard(c) {
|
|
const div = document.createElement("div");
|
|
div.className = "course-card";
|
|
div.innerHTML = "<b>" + c.title + "</b> by " + (c.author_name || c.AuthorName || "?") +
|
|
" <span class='muted'>(" + c.visibility + ")</span><br>" +
|
|
"<span class='muted'>" + (c.description || "") + "</span><br>" +
|
|
"<a href='#' data-id='" + c.id + "'>Open</a>";
|
|
div.querySelector("a").addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
openCourse(c.id);
|
|
});
|
|
return div;
|
|
}
|
|
|
|
async function loadPublic() {
|
|
const res = await api.get("/api/courses");
|
|
const list = document.getElementById("public-list");
|
|
list.innerHTML = "";
|
|
(res.courses || []).forEach((c) => list.appendChild(courseCard(c)));
|
|
}
|
|
|
|
async function loadMine() {
|
|
const res = await api.get("/api/me/courses");
|
|
const list = document.getElementById("my-list");
|
|
if (!res.ok) {
|
|
list.textContent = "log in to see your courses";
|
|
return;
|
|
}
|
|
list.innerHTML = "";
|
|
(res.courses || []).forEach((c) => list.appendChild(courseCard(c)));
|
|
}
|
|
|
|
async function openCourse(id) {
|
|
currentCourseID = id;
|
|
const res = await api.get("/api/courses/" + id);
|
|
document.getElementById("detail-panel").style.display = "block";
|
|
document.getElementById("chapter-detail").style.display = "none";
|
|
document.getElementById("detail-title").textContent = res.title || "(not found)";
|
|
document.getElementById("detail-meta").textContent =
|
|
"by " + res.author + " - " + res.visibility;
|
|
|
|
const list = document.getElementById("chapter-list");
|
|
list.innerHTML = "";
|
|
(res.chapters || []).forEach((ch) => {
|
|
const a = document.createElement("a");
|
|
a.href = "#";
|
|
a.textContent = ch.ordinal + ". " + ch.title;
|
|
a.style.display = "block";
|
|
a.addEventListener("click", (e) => {
|
|
e.preventDefault();
|
|
openChapter(id, ch.id);
|
|
});
|
|
list.appendChild(a);
|
|
});
|
|
|
|
const me = await api.get("/api/me");
|
|
document.getElementById("add-chapter-box").style.display = me.username ? "block" : "none";
|
|
}
|
|
|
|
async function openChapter(courseID, chapterID) {
|
|
const res = await api.get("/api/courses/" + courseID + "/chapters/" + chapterID);
|
|
const box = document.getElementById("chapter-detail");
|
|
box.style.display = "block";
|
|
box.innerHTML = "<h4>" + res.title + "</h4><p>" + (res.annotation || "") + "</p>" +
|
|
"<p class='muted'>moves: " + (res.moves ? res.moves.length : 0) + "</p>" +
|
|
"<p><b>Solution:</b> " + (res.solution_note || "(none)") + "</p>";
|
|
}
|
|
|
|
document.getElementById("c-create").addEventListener("click", async () => {
|
|
const res = await api.post("/api/courses", {
|
|
title: document.getElementById("c-title").value,
|
|
description: document.getElementById("c-desc").value,
|
|
visibility: document.getElementById("c-vis").value,
|
|
variant: 0,
|
|
start_fen: "",
|
|
rule_flags: 0,
|
|
});
|
|
const msg = document.getElementById("c-msg");
|
|
if (res.ok) {
|
|
msg.textContent = "created course #" + res.id;
|
|
loadPublic();
|
|
loadMine();
|
|
} else {
|
|
msg.textContent = res.error || "could not create course";
|
|
}
|
|
});
|
|
|
|
document.getElementById("ch-add").addEventListener("click", async () => {
|
|
if (!currentCourseID) return;
|
|
const res = await api.post("/api/courses/" + currentCourseID + "/chapters", {
|
|
ordinal: 1,
|
|
title: document.getElementById("ch-title").value,
|
|
annotation: document.getElementById("ch-annotation").value,
|
|
moves: [],
|
|
solution_note: document.getElementById("ch-solution").value,
|
|
});
|
|
if (res.ok) {
|
|
openCourse(currentCourseID);
|
|
} else {
|
|
alert(res.error || "could not add chapter");
|
|
}
|
|
});
|
|
|
|
loadPublic();
|
|
loadMine();
|
|
</script>
|
|
</body>
|
|
</html>
|