190 lines
17 KiB
HTML
190 lines
17 KiB
HTML
<!DOCTYPE html>
|
||
<html lang="ru" xmlns:th="http://www.thymeleaf.org" th:replace="~{fragments/base :: layout(~{::title}, ~{::#content})}">
|
||
<head><title th:text="${chapter.title} + ' — LMS'">Глава</title></head>
|
||
<body>
|
||
<div id="content" th:attr="data-csrf=${csrfToken},data-sort-scope='chapter',data-chapter-id=${chapter.id}">
|
||
<nav class="text-sm mb-4 breadcrumb">
|
||
<a th:href="@{/learn}" class="nav-link">Материалы</a>
|
||
<span class="nav-sep">/</span>
|
||
<span th:text="${chapter.title}">Глава</span>
|
||
</nav>
|
||
|
||
<h1 class="page-title">
|
||
<span th:text="${chapter.title}">Глава</span>
|
||
<span th:if="${!chapter.published}" class="badge badge-warn ml-2">скрыто</span>
|
||
</h1>
|
||
|
||
<div th:if="${currentUser != null and currentUser.admin}" class="flex flex-wrap gap-2 mb-4">
|
||
<button class="btn btn-primary" type="button" data-modal="modal-new-section">+ Раздел</button>
|
||
<button class="mini-btn" type="button" data-modal="modal-rename-chapter" title="Переименовать главу" aria-label="Переименовать главу"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.8 2.8 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></button>
|
||
<form class="inline-form" th:action="@{/admin/content/chapters/toggle-published}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="id" th:value="${chapter.id}">
|
||
<input type="hidden" name="published" th:value="${!chapter.published}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="mini-btn" type="submit" th:if="${chapter.published}" title="Скрыть главу" aria-label="Скрыть главу"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg></button>
|
||
<button class="mini-btn" type="submit" th:unless="${chapter.published}" title="Опубликовать главу" aria-label="Опубликовать главу"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/><line x1="3" y1="3" x2="21" y2="21"/></svg></button>
|
||
</form>
|
||
<form class="inline-form" th:action="@{/admin/content/chapters/{id}/delete(id=${chapter.id})}" method="post" data-confirm="Удалить главу со всеми разделами и статьями?">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${backParent}">
|
||
<button class="mini-btn danger" type="submit" title="Удалить главу со всеми разделами и статьями" aria-label="Удалить главу со всеми разделами и статьями"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg></button>
|
||
</form>
|
||
</div>
|
||
|
||
<div th:if="${currentUser != null and currentUser.admin}" class="card card-body text-sm text-muted mb-4">
|
||
Перетаскивайте за значок руки слева, чтобы менять порядок разделов и переносить статьи
|
||
между разделами этой главы. Порядок сохраняется сразу.
|
||
</div>
|
||
<div th:if="${currentUser != null and currentUser.admin}" id="sort-status" class="sort-status" hidden>
|
||
<span id="sort-status-text">Изменения не сохранены…</span>
|
||
</div>
|
||
|
||
<div th:if="${#lists.isEmpty(chapter.sections)}" class="card card-body text-muted">
|
||
В этой главе пока нет разделов.
|
||
</div>
|
||
|
||
<div class="card card-body chapter-card mb-4" data-section-list>
|
||
<div th:each="section : ${chapter.sections}" class="sub-acc collapsed"
|
||
th:attr="data-section-id=${section.id}">
|
||
<div class="sub-head sort-row">
|
||
<span th:if="${currentUser != null and currentUser.admin}" class="drag-handle" draggable="true"
|
||
th:attr="data-drag-kind='section',data-drag-id=${section.id}"
|
||
title="Перетащите мышью: изменить порядок разделов">⠿</span>
|
||
<button type="button" class="sub-toggle" aria-expanded="false"
|
||
title="Свернуть или развернуть раздел">
|
||
<span class="sub-arrow" aria-hidden="true"></span>
|
||
</button>
|
||
<a class="group-title sort-title m-0"
|
||
th:href="@{/learn/{c}/{s}(c=${chapter.slug}, s=${section.slug})}"
|
||
th:text="${section.title}">Раздел</a>
|
||
<span th:if="${!section.published}" class="badge badge-warn">скрыто</span>
|
||
<div th:if="${currentUser != null and currentUser.admin}" class="sort-actions">
|
||
<button class="mini-btn" type="button" th:attr="data-modal=|modal-rename-section-${section.id}|" title="Переименовать раздел" aria-label="Переименовать раздел"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M17 3a2.8 2.8 0 1 1 4 4L7.5 20.5 2 22l1.5-5.5Z"/></svg></button>
|
||
<form class="inline-form" th:action="@{/admin/content/sections/toggle-published}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="id" th:value="${section.id}">
|
||
<input type="hidden" name="published" th:value="${!section.published}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="mini-btn" type="submit" th:if="${section.published}" title="Скрыть раздел" aria-label="Скрыть раздел"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg></button>
|
||
<button class="mini-btn" type="submit" th:unless="${section.published}" title="Опубликовать раздел" aria-label="Опубликовать раздел"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/><line x1="3" y1="3" x2="21" y2="21"/></svg></button>
|
||
</form>
|
||
<button class="mini-btn" type="button" th:attr="data-modal=|modal-move-${section.id}|" title="Перенести статьи и удалить" aria-label="Перенести статьи и удалить"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M18 11V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2"/><path d="M14 10V4a2 2 0 0 0-2-2a2 2 0 0 0-2 2"/><path d="M10 10.5V6a2 2 0 0 0-2-2a2 2 0 0 0-2 2v8"/><path d="M18 8a2 2 0 1 1 4 0v6a8 8 0 0 1-8 8h-2c-2.8 0-4.5-.86-5.99-2.34l-3.6-3.6a2 2 0 0 1 2.83-2.82L7 15"/></svg></button>
|
||
<form class="inline-form" th:action="@{/admin/content/sections/{id}/delete(id=${section.id})}" method="post" data-confirm="Удалить раздел вместе со статьями?">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="mini-btn danger" type="submit" title="Удалить раздел вместе со статьями" aria-label="Удалить раздел вместе со статьями"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><polyline points="3 6 5 6 21 6"/><path d="M19 6l-1 14a2 2 0 0 1-2 2H8a2 2 0 0 1-2-2L5 6"/><path d="M10 11v6"/><path d="M14 11v6"/><path d="M9 6V4a1 1 0 0 1 1-1h4a1 1 0 0 1 1 1v2"/></svg></button>
|
||
</form>
|
||
</div>
|
||
</div>
|
||
|
||
<div class="section-body">
|
||
<ul class="sort-list text-sm" data-article-list>
|
||
<li th:each="article : ${section.articles}" th:attr="data-article-id=${article.id}">
|
||
<span th:if="${currentUser != null and currentUser.admin}" class="drag-handle" draggable="true"
|
||
th:attr="data-drag-kind='article',data-drag-id=${article.id}"
|
||
title="Перетащите мышью: изменить порядок или перенести в другой раздел">⠿</span>
|
||
<a class="sort-title"
|
||
th:href="@{/learn/{c}/{s}/{a}(c=${chapter.slug}, s=${section.slug}, a=${article.slug})}"
|
||
th:text="${article.title}">Статья</a>
|
||
<span th:if="${!article.published}" class="badge badge-warn">скрыто</span>
|
||
<div th:if="${currentUser != null and currentUser.admin}" class="sort-actions">
|
||
<a class="btn btn-secondary"
|
||
th:href="@{/learn/{c}/{s}/{a}(c=${chapter.slug}, s=${section.slug}, a=${article.slug}, edit=1)}">Править</a>
|
||
<form class="inline-form" th:action="@{/admin/content/articles/toggle-published}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="id" th:value="${article.id}">
|
||
<input type="hidden" name="published" th:value="${!article.published}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<button class="mini-btn" type="submit" th:if="${article.published}" title="Скрыть статью" aria-label="Скрыть статью"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/></svg></button>
|
||
<button class="mini-btn" type="submit" th:unless="${article.published}" title="Опубликовать статью" aria-label="Опубликовать статью"><svg class="cell-ico" viewBox="0 0 24 24" fill="none" stroke="currentColor" stroke-width="2" stroke-linecap="round" stroke-linejoin="round"><path d="M1 12s4-7 11-7 11 7 11 7-4 7-11 7S1 12 1 12z"/><circle cx="12" cy="12" r="3"/><line x1="3" y1="3" x2="21" y2="21"/></svg></button>
|
||
</form>
|
||
</div>
|
||
</li>
|
||
<li th:if="${#lists.isEmpty(section.articles)}" class="text-muted">Статей пока нет</li>
|
||
</ul>
|
||
</div>
|
||
|
||
<th:block th:if="${currentUser != null and currentUser.admin}">
|
||
<dialog th:id="|modal-rename-section-${section.id}|" class="modal">
|
||
<div class="modal-header">
|
||
<h2 class="modal-title">Переименовать раздел</h2>
|
||
<button class="modal-close" type="button" aria-label="Закрыть"
|
||
th:attr="data-modal=|modal-rename-section-${section.id}|">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form class="form-stack" th:action="@{/admin/content/sections/{id}/rename(id=${section.id})}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<div><label class="label">Название</label>
|
||
<input class="input" name="title" th:value="${section.title}" required></div>
|
||
<button class="btn btn-primary" type="submit">Сохранить</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
<dialog th:id="|modal-move-${section.id}|" class="modal">
|
||
<div class="modal-header">
|
||
<h2 class="modal-title">Перенести статьи из раздела</h2>
|
||
<button class="modal-close" type="button" aria-label="Закрыть"
|
||
th:attr="data-modal=|modal-move-${section.id}|">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form class="form-stack" th:action="@{/admin/content/sections/{id}/delete(id=${section.id})}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<p class="text-sm text-muted">Выберите раздел-приёмник: статьи перенесутся туда, а текущий раздел удалится.</p>
|
||
<p th:if="${#lists.size(sectionChoices) < 2}" class="text-sm text-muted">
|
||
<b>Других разделов нет</b> — при подтверждении статьи будут удалены вместе с разделом.
|
||
</p>
|
||
<div><label class="label">Перенести в раздел</label>
|
||
<select class="input" name="moveTo">
|
||
<option th:each="pair : ${sectionChoices}"
|
||
th:if="${pair['id'] != section.id}"
|
||
th:value="${pair['id']}" th:text="${pair['label']}">—</option>
|
||
</select></div>
|
||
<button class="btn btn-primary" type="submit">Перенести и удалить</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
</th:block>
|
||
</div>
|
||
</div>
|
||
|
||
<dialog id="modal-rename-chapter" class="modal">
|
||
<div class="modal-header">
|
||
<h2 class="modal-title">Переименовать главу</h2>
|
||
<button class="modal-close" type="button" aria-label="Закрыть">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form class="form-stack" th:action="@{/admin/content/chapters/{id}/rename(id=${chapter.id})}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<div><label class="label" for="chTitle">Название</label>
|
||
<input class="input" id="chTitle" name="title" th:value="${chapter.title}" required></div>
|
||
<button class="btn btn-primary" type="submit">Сохранить</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
|
||
<dialog id="modal-new-section" class="modal">
|
||
<div class="modal-header">
|
||
<h2 class="modal-title">Новый раздел в главе</h2>
|
||
<button class="modal-close" type="button" aria-label="Закрыть">✕</button>
|
||
</div>
|
||
<div class="modal-body">
|
||
<form class="form-stack" th:action="@{/admin/content/sections/create}" method="post">
|
||
<input type="hidden" name="_csrf" th:value="${csrfToken}">
|
||
<input type="hidden" name="chapterId" th:value="${chapter.id}">
|
||
<input type="hidden" name="back" th:value="${back}">
|
||
<div><label class="label" for="secNewTitle">Название раздела</label>
|
||
<input class="input" id="secNewTitle" name="title" required></div>
|
||
<button class="btn btn-primary" type="submit">Создать</button>
|
||
</form>
|
||
</div>
|
||
</dialog>
|
||
|
||
<script th:src="@{/js/content-sort.js(v='11')}" defer></script>
|
||
</div>
|
||
</body>
|
||
</html>
|