327 lines
13 KiB
HTML
327 lines
13 KiB
HTML
<!DOCTYPE html>
|
|
<html lang="en">
|
|
<head>
|
|
<meta charset="UTF-8">
|
|
<meta name="viewport" content="width=device-width, initial-scale=1.0">
|
|
<title>Manage Group</title>
|
|
<link href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" rel="stylesheet">
|
|
<style>
|
|
body.dark-mode {
|
|
background-color: #121212;
|
|
color: #ffffff;
|
|
}
|
|
.card.dark-mode {
|
|
background-color: #1e1e1e;
|
|
color: #ffffff;
|
|
}
|
|
.dark-mode label, .dark-mode th, .dark-mode td {
|
|
color: #ffffff;
|
|
}
|
|
@media (max-width: 768px) {
|
|
h1 {
|
|
font-size: 1.5rem;
|
|
}
|
|
.btn {
|
|
font-size: 0.9rem;
|
|
padding: 0.5rem 1rem;
|
|
}
|
|
.card {
|
|
margin-bottom: 1rem;
|
|
}
|
|
}
|
|
|
|
.sortable-list li {
|
|
cursor: move;
|
|
transition: background-color 0.2s ease;
|
|
}
|
|
|
|
.sortable-list li.dragging {
|
|
opacity: 0.5;
|
|
background-color: #f8f9fa;
|
|
}
|
|
|
|
.drag-handle {
|
|
cursor: grab;
|
|
color: #aaa;
|
|
font-size: 1.2rem;
|
|
}
|
|
|
|
.drag-over {
|
|
border-top: 2px solid #0d6efd;
|
|
}
|
|
</style>
|
|
</head>
|
|
<body class="{{ 'dark-mode' if theme == 'dark' else '' }}">
|
|
<div class="container py-5">
|
|
<h1 class="text-center mb-4">Manage Group: {{ group.name }}</h1>
|
|
|
|
<!-- Group Information Card -->
|
|
<div class="card mb-4 {{ 'dark-mode' if theme == 'dark' else '' }}">
|
|
<div class="card-header bg-info text-white">
|
|
<h2>Group Info</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<p><strong>Group Name:</strong> {{ group.name }}</p>
|
|
<p><strong>Number of Players:</strong> {{ group.players|length }}</p>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- List of Players in the Group -->
|
|
<div class="card mb-4 {{ 'dark-mode' if theme == 'dark' else '' }}">
|
|
<div class="card-header bg-secondary text-white">
|
|
<h2>Players in Group</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
<ul class="list-group">
|
|
{% for player in group.players %}
|
|
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
<div>
|
|
<strong>{{ player.username }}</strong> ({{ player.hostname }})
|
|
</div>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Manage Media Section -->
|
|
<div class="card mb-4 {{ 'dark-mode' if theme == 'dark' else '' }}">
|
|
<div class="card-header bg-info text-white">
|
|
<h2>Manage Media</h2>
|
|
</div>
|
|
<div class="card-body">
|
|
{% if content %}
|
|
<!-- Bulk Actions Controls -->
|
|
<div class="row mb-3">
|
|
<div class="col-md-6">
|
|
<div class="form-check">
|
|
<input class="form-check-input" type="checkbox" id="selectAll">
|
|
<label class="form-check-label" for="selectAll">
|
|
Select All
|
|
</label>
|
|
</div>
|
|
</div>
|
|
<div class="col-md-6 text-end">
|
|
<button type="button" class="btn btn-danger" id="bulkDeleteBtn" style="display:none;" onclick="confirmBulkDelete()">
|
|
<i class="bi bi-trash"></i> Delete Selected
|
|
</button>
|
|
</div>
|
|
</div>
|
|
|
|
<ul class="list-group sortable-list" id="groupMediaList">
|
|
{% for media in content %}
|
|
<li class="list-group-item d-flex align-items-center {{ 'dark-mode' if theme == 'dark' else '' }}"
|
|
draggable="true"
|
|
data-id="{{ media.id }}"
|
|
data-position="{{ loop.index0 }}">
|
|
<!-- Checkbox for bulk selection -->
|
|
<div class="me-2">
|
|
<input class="form-check-input media-checkbox"
|
|
type="checkbox"
|
|
name="selected_content"
|
|
value="{{ media.id }}">
|
|
</div>
|
|
|
|
<!-- Drag handle -->
|
|
<div class="drag-handle me-2" title="Drag to reorder">
|
|
<i class="bi bi-grip-vertical"></i>
|
|
☰
|
|
</div>
|
|
|
|
<!-- Media Thumbnail and Name -->
|
|
<div class="flex-grow-1 mb-2 mb-md-0 d-flex align-items-center">
|
|
<img src="{{ url_for('static', filename='uploads/' ~ media.file_name) }}"
|
|
alt="thumbnail"
|
|
style="width: 48px; height: 48px; object-fit: cover; margin-right: 10px; border-radius: 4px;"
|
|
onerror="this.style.display='none';">
|
|
<p class="mb-0"><strong>Media Name:</strong> {{ media.file_name }}</p>
|
|
</div>
|
|
<<<<<<< HEAD
|
|
=======
|
|
|
|
>>>>>>> 2255cc2 (Show media thumbnails in manage group page, matching player page style)
|
|
<form action="{{ url_for('edit_group_media_route', group_id=group.id, content_id=media.id) }}" method="post" class="d-flex align-items-center">
|
|
<div class="input-group me-2">
|
|
<span class="input-group-text">seconds</span>
|
|
<input type="number" class="form-control {{ 'dark-mode' if theme == 'dark' else '' }}" name="duration" value="{{ media.duration }}" required>
|
|
</div>
|
|
<button type="submit" class="btn btn-warning me-2">Edit</button>
|
|
</form>
|
|
<form action="{{ url_for('delete_group_media_route', group_id=group.id, content_id=media.id) }}" method="post" style="display:inline;">
|
|
<button type="submit" class="btn btn-danger" onclick="return confirm('Are you sure you want to delete this media?');">Delete</button>
|
|
</form>
|
|
</li>
|
|
{% endfor %}
|
|
</ul>
|
|
<!-- Add a save button for the reordering -->
|
|
<button id="saveGroupOrder" class="btn btn-success mt-3">Save Playlist Order</button>
|
|
{% else %}
|
|
<p class="text-center">No media uploaded for this group.</p>
|
|
{% endif %}
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Upload Media Button -->
|
|
<div class="text-center mb-4">
|
|
<a href="{{ url_for('upload_content', target_type='group', target_id=group.id, return_url=url_for('manage_group', group_id=group.id)) }}" class="btn btn-primary btn-lg">Go to Upload Media</a>
|
|
</div>
|
|
|
|
<!-- Back to Dashboard Button -->
|
|
<a href="{{ url_for('dashboard') }}" class="btn btn-secondary">Back to Dashboard</a>
|
|
</div>
|
|
|
|
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js"></script>
|
|
<script>
|
|
document.addEventListener('DOMContentLoaded', function() {
|
|
const groupMediaList = document.getElementById('groupMediaList');
|
|
let draggedItem = null;
|
|
|
|
// Initialize drag events for all items
|
|
const items = groupMediaList.querySelectorAll('li');
|
|
items.forEach(item => {
|
|
// Drag start
|
|
item.addEventListener('dragstart', function(e) {
|
|
draggedItem = item;
|
|
setTimeout(() => {
|
|
item.classList.add('dragging');
|
|
}, 0);
|
|
});
|
|
|
|
// Drag end
|
|
item.addEventListener('dragend', function() {
|
|
item.classList.remove('dragging');
|
|
draggedItem = null;
|
|
updatePositions();
|
|
});
|
|
|
|
// Drag over
|
|
item.addEventListener('dragover', function(e) {
|
|
e.preventDefault();
|
|
if (item !== draggedItem) {
|
|
const rect = item.getBoundingClientRect();
|
|
const y = e.clientY - rect.top;
|
|
const height = rect.height;
|
|
|
|
if (y < height / 2) {
|
|
groupMediaList.insertBefore(draggedItem, item);
|
|
} else {
|
|
groupMediaList.insertBefore(draggedItem, item.nextSibling);
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Save button click handler
|
|
document.getElementById('saveGroupOrder').addEventListener('click', function() {
|
|
// Collect new order
|
|
const newOrder = [];
|
|
groupMediaList.querySelectorAll('li').forEach((item, index) => {
|
|
newOrder.push({
|
|
id: item.dataset.id,
|
|
position: index
|
|
});
|
|
});
|
|
|
|
// Send to server
|
|
fetch('{{ url_for("update_group_content_order_route", group_id=group.id) }}', {
|
|
method: 'POST',
|
|
headers: {
|
|
'Content-Type': 'application/json',
|
|
'X-CSRFToken': '{{ csrf_token() if csrf_token else "" }}'
|
|
},
|
|
body: JSON.stringify({items: newOrder})
|
|
})
|
|
.then(response => response.json())
|
|
.then(data => {
|
|
if (data.success) {
|
|
alert('Playlist order updated successfully!');
|
|
console.log('Group playlist update successful:', data);
|
|
} else {
|
|
alert('Error updating playlist order: ' + (data.error || 'Unknown error'));
|
|
console.error('Failed to update group playlist:', data);
|
|
}
|
|
})
|
|
.catch(error => {
|
|
console.error('Error:', error);
|
|
alert('An error occurred while updating the playlist order.');
|
|
});
|
|
});
|
|
|
|
// Update positions in the UI
|
|
function updatePositions() {
|
|
groupMediaList.querySelectorAll('li').forEach((item, index) => {
|
|
item.dataset.position = index;
|
|
});
|
|
}
|
|
|
|
// Bulk selection functionality
|
|
const selectAllCheckbox = document.getElementById('selectAll');
|
|
const mediaCheckboxes = document.querySelectorAll('.media-checkbox');
|
|
const bulkDeleteBtn = document.getElementById('bulkDeleteBtn');
|
|
|
|
// Select all functionality
|
|
if (selectAllCheckbox) {
|
|
selectAllCheckbox.addEventListener('change', function() {
|
|
mediaCheckboxes.forEach(checkbox => {
|
|
checkbox.checked = this.checked;
|
|
});
|
|
updateBulkDeleteButton();
|
|
});
|
|
}
|
|
|
|
// Individual checkbox change
|
|
mediaCheckboxes.forEach(checkbox => {
|
|
checkbox.addEventListener('change', function() {
|
|
updateSelectAllState();
|
|
updateBulkDeleteButton();
|
|
});
|
|
});
|
|
|
|
function updateSelectAllState() {
|
|
const checkedBoxes = Array.from(mediaCheckboxes).filter(cb => cb.checked);
|
|
|
|
if (selectAllCheckbox) {
|
|
selectAllCheckbox.checked = checkedBoxes.length === mediaCheckboxes.length && mediaCheckboxes.length > 0;
|
|
selectAllCheckbox.indeterminate = checkedBoxes.length > 0 && checkedBoxes.length < mediaCheckboxes.length;
|
|
}
|
|
}
|
|
|
|
function updateBulkDeleteButton() {
|
|
const checkedBoxes = Array.from(mediaCheckboxes).filter(cb => cb.checked);
|
|
if (bulkDeleteBtn) {
|
|
bulkDeleteBtn.style.display = checkedBoxes.length > 0 ? 'inline-block' : 'none';
|
|
}
|
|
}
|
|
});
|
|
|
|
function confirmBulkDelete() {
|
|
const checkedBoxes = Array.from(document.querySelectorAll('.media-checkbox:checked'));
|
|
if (checkedBoxes.length === 0) {
|
|
alert('No media files selected.');
|
|
return;
|
|
}
|
|
|
|
const count = checkedBoxes.length;
|
|
const message = `Are you sure you want to delete ${count} selected media file${count > 1 ? 's' : ''}? This action cannot be undone.`;
|
|
|
|
if (confirm(message)) {
|
|
// Create a form with selected IDs
|
|
const form = document.createElement('form');
|
|
form.method = 'POST';
|
|
form.action = '{{ url_for("bulk_delete_group_content", group_id=group.id) }}';
|
|
|
|
checkedBoxes.forEach(checkbox => {
|
|
const input = document.createElement('input');
|
|
input.type = 'hidden';
|
|
input.name = 'selected_content';
|
|
input.value = checkbox.value;
|
|
form.appendChild(input);
|
|
});
|
|
|
|
document.body.appendChild(form);
|
|
form.submit();
|
|
}
|
|
}
|
|
</script>
|
|
</body>
|
|
</html> |