admin panel and password protection
This commit is contained in:
164
index.html
164
index.html
@@ -3,7 +3,7 @@
|
||||
<head>
|
||||
<meta charset="UTF-8" />
|
||||
<meta name="viewport" content="width=device-width, initial-scale=1.0" />
|
||||
<title>Christiana Varner - Portland State University - Graduation 2025</title>
|
||||
<title>Album Viewer</title>
|
||||
<style>
|
||||
body {
|
||||
font-family: Arial, sans-serif;
|
||||
@@ -24,7 +24,9 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<h1 style="text-align:center;">Christiana Varner - Portland State University - Graduation 2025</h1>
|
||||
|
||||
<h1 style="text-align:center;">Album Viewer</h1>
|
||||
<!-- Album selector removed. Album is chosen via URL parameter. -->
|
||||
<a href="Download_All_Photos.zip" id="download-all" style="position:fixed;top:20px;left:20px;z-index:1000;display:inline-block;padding:8px 16px;background:#0078d4;color:#fff;text-decoration:none;border-radius:4px;font-weight:bold;">Download All</a>
|
||||
<button id="select-images" style="position:fixed;top:20px;left:160px;z-index:1000;display:inline-block;padding:8px 16px;background:#0078d4;color:#fff;border:none;border-radius:4px;font-weight:bold;cursor:pointer;">Select</button>
|
||||
<div class="gallery" id="gallery"></div>
|
||||
@@ -33,60 +35,130 @@
|
||||
const gallery = document.getElementById('gallery');
|
||||
const selectBtn = document.getElementById('select-images');
|
||||
let downloadBtn = null;
|
||||
let albums = {};
|
||||
|
||||
function getQueryParam(name) {
|
||||
const urlParams = new URLSearchParams(window.location.search);
|
||||
return urlParams.get(name);
|
||||
}
|
||||
|
||||
function renderGallery(images) {
|
||||
gallery.innerHTML = '';
|
||||
images.forEach((imgObj, idx) => {
|
||||
const itemDiv = document.createElement('div');
|
||||
itemDiv.style.position = 'relative';
|
||||
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.className = 'img-checkbox';
|
||||
checkbox.style.position = 'absolute';
|
||||
checkbox.style.top = '8px';
|
||||
checkbox.style.left = '8px';
|
||||
checkbox.value = imgObj.full;
|
||||
checkbox.style.display = 'none';
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = imgObj.full;
|
||||
link.target = '_blank';
|
||||
const img = document.createElement('img');
|
||||
img.src = imgObj.thumb;
|
||||
img.alt = imgObj.full;
|
||||
link.appendChild(img);
|
||||
|
||||
itemDiv.addEventListener('click', function(e) {
|
||||
if (checkbox.style.display === 'block') {
|
||||
if (e.target === img || e.target === itemDiv) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
});
|
||||
|
||||
itemDiv.appendChild(checkbox);
|
||||
itemDiv.appendChild(link);
|
||||
gallery.appendChild(itemDiv);
|
||||
});
|
||||
}
|
||||
|
||||
fetch('list-images.php')
|
||||
.then(response => response.json())
|
||||
.then(images => {
|
||||
images.forEach((imgObj, idx) => {
|
||||
// Container for image and checkbox
|
||||
const itemDiv = document.createElement('div');
|
||||
itemDiv.style.position = 'relative';
|
||||
|
||||
// Checkbox (hidden by default)
|
||||
const checkbox = document.createElement('input');
|
||||
checkbox.type = 'checkbox';
|
||||
checkbox.className = 'img-checkbox';
|
||||
checkbox.style.position = 'absolute';
|
||||
checkbox.style.top = '8px';
|
||||
checkbox.style.left = '8px';
|
||||
checkbox.value = imgObj.full;
|
||||
checkbox.style.display = 'none';
|
||||
|
||||
// Image link
|
||||
const link = document.createElement('a');
|
||||
link.href = imgObj.full;
|
||||
link.target = '_blank';
|
||||
const img = document.createElement('img');
|
||||
img.src = imgObj.thumb;
|
||||
img.alt = imgObj.full;
|
||||
link.appendChild(img);
|
||||
|
||||
// Make image clickable for selection in select mode
|
||||
itemDiv.addEventListener('click', function(e) {
|
||||
// Only toggle if in select mode (checkboxes visible)
|
||||
if (checkbox.style.display === 'block') {
|
||||
// Prevent link from opening when selecting
|
||||
if (e.target === img || e.target === itemDiv) {
|
||||
checkbox.checked = !checkbox.checked;
|
||||
e.preventDefault();
|
||||
}
|
||||
}
|
||||
.then(data => {
|
||||
albums = data;
|
||||
const albumName = getQueryParam('album');
|
||||
if (!albumName) {
|
||||
// Landing page: show album links
|
||||
gallery.innerHTML = '<div style="text-align:center;padding:40px 0;"><h2>Welcome!</h2><p>Select an album to view photos:</p></div>';
|
||||
const albumList = document.createElement('div');
|
||||
albumList.style.display = 'flex';
|
||||
albumList.style.flexWrap = 'wrap';
|
||||
albumList.style.justifyContent = 'center';
|
||||
albumList.style.gap = '20px';
|
||||
Object.keys(albums).forEach(album => {
|
||||
const link = document.createElement('a');
|
||||
link.href = `index.html?album=${encodeURIComponent(album)}`;
|
||||
link.textContent = album + (albums[album].protected ? ' 🔒' : '');
|
||||
link.style.display = 'inline-block';
|
||||
link.style.padding = '16px 32px';
|
||||
link.style.background = '#0078d4';
|
||||
link.style.color = '#fff';
|
||||
link.style.borderRadius = '8px';
|
||||
link.style.fontWeight = 'bold';
|
||||
link.style.fontSize = '20px';
|
||||
link.style.textDecoration = 'none';
|
||||
link.style.boxShadow = '0 2px 8px rgba(0,0,0,0.12)';
|
||||
albumList.appendChild(link);
|
||||
});
|
||||
gallery.appendChild(albumList);
|
||||
selectBtn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
if (!albums[albumName]) {
|
||||
gallery.innerHTML = '<p style="color:red;">Album not found. Please specify a valid album in the URL (e.g., ?album=Album1).</p>';
|
||||
selectBtn.style.display = 'none';
|
||||
return;
|
||||
}
|
||||
// Check if album is protected
|
||||
if (albums[albumName].protected) {
|
||||
let password = localStorage.getItem('album_pw_' + albumName) || '';
|
||||
function requestImages(pw) {
|
||||
fetch(`list-images.php?album=${encodeURIComponent(albumName)}&password=${encodeURIComponent(pw)}`)
|
||||
.then(resp => {
|
||||
if (resp.status === 403) {
|
||||
throw new Error('Password required');
|
||||
}
|
||||
return resp.json();
|
||||
})
|
||||
.then(images => {
|
||||
renderGallery(images);
|
||||
selectBtn.style.display = 'inline-block';
|
||||
localStorage.setItem('album_pw_' + albumName, pw);
|
||||
})
|
||||
.catch(() => {
|
||||
gallery.innerHTML = `<div style='text-align:center;padding:40px 0;'><h2>Password Required</h2><form id='pwform'><input type='password' id='album_pw' placeholder='Enter album password' style='padding:8px;font-size:18px;border-radius:4px;border:1px solid #ccc;width:220px;'><button type='submit' style='margin-left:12px;padding:8px 16px;background:#0078d4;color:#fff;border:none;border-radius:4px;font-weight:bold;cursor:pointer;'>View Album</button></form><div id='pwerror' style='color:red;margin-top:12px;'></div></div>`;
|
||||
selectBtn.style.display = 'none';
|
||||
document.getElementById('pwform').onsubmit = function(e) {
|
||||
e.preventDefault();
|
||||
const pwTry = document.getElementById('album_pw').value;
|
||||
requestImages(pwTry);
|
||||
};
|
||||
});
|
||||
}
|
||||
requestImages(password);
|
||||
return;
|
||||
}
|
||||
// Not protected, fetch images
|
||||
fetch(`list-images.php?album=${encodeURIComponent(albumName)}`)
|
||||
.then(resp => resp.json())
|
||||
.then(images => {
|
||||
renderGallery(images);
|
||||
selectBtn.style.display = 'inline-block';
|
||||
});
|
||||
|
||||
itemDiv.appendChild(checkbox);
|
||||
itemDiv.appendChild(link);
|
||||
gallery.appendChild(itemDiv);
|
||||
});
|
||||
|
||||
// Add select button logic
|
||||
selectBtn.addEventListener('click', () => {
|
||||
// Show checkboxes
|
||||
document.querySelectorAll('.img-checkbox').forEach(cb => {
|
||||
cb.style.display = 'block';
|
||||
});
|
||||
// Hide select button
|
||||
selectBtn.style.display = 'none';
|
||||
// Create and show download selected button
|
||||
downloadBtn = document.createElement('button');
|
||||
downloadBtn.id = 'download-selected';
|
||||
downloadBtn.textContent = 'Download Selected';
|
||||
|
||||
Reference in New Issue
Block a user