Files
GoNetKit/web/pwpush.html
2025-07-17 21:52:52 +01:00

1071 lines
29 KiB
HTML
Raw Blame History

This file contains invisible Unicode characters
This file contains invisible Unicode characters that are indistinguishable to humans but may be processed differently by a computer. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
{{template "base.html" .}}
{{define "title"}}Password Pusher - Secure Text Sharing{{end}}
{{define "head"}}
{{if .Success}}
<meta name="success-data" content='{"id":"{{.ID}}","url":"{{.PushURL}}","expiresAt":"{{.ExpiresAt}}"}'>
{{end}}
<style>
:root {
--bg-color: #1e1e1e;
--text-color: #e0e0e0;
--section-bg: #2d2d2d;
--border-color: #404040;
--highlight: #3c5c7c;
--success: #4caf50;
--warning: #ff9800;
--error: #f44336;
--danger: #f44336;
--info: #2196f3;
--muted-color: #999;
}
body {
background-color: var(--bg-color);
color: var(--text-color);
}
.container {
background-color: var(--bg-color);
color: var(--text-color);
}
input, textarea {
background-color: var(--section-bg);
color: var(--text-color);
border: 1px solid var(--border-color);
}
.push-form, .info-section, .history-section {
background-color: var(--section-bg);
border: 1px solid var(--border-color);
}
.history-header {
background-color: #333;
border-bottom: 1px solid var(--border-color);
}
.history-stats {
background-color: #333;
border-bottom: 1px solid var(--border-color);
}
.stat-badge {
background-color: var(--section-bg);
border: 1px solid var(--border-color);
color: var(--text-color);
}
.history-table th {
background-color: #333;
color: var(--text-color);
border-bottom: 2px solid var(--border-color);
}
.history-table td {
border-bottom: 1px solid var(--border-color);
color: var(--text-color);
}
.history-table tr:hover:not(.empty-row) {
background-color: #333;
}
.preview-text {
background-color: #333;
color: var(--text-color);
}
.btn-danger {
background: var(--error);
}
.btn-sm {
font-size: 12px;
padding: 6px 12px;
}
.notes-cell {
max-width: 120px;
font-size: 12px;
}
.notes-text {
color: #aaa;
font-style: italic;
}
.container {
max-width: 800px;
margin: 0 auto;
padding: 20px;
}
.alert {
padding: 20px;
margin: 20px 0;
border-radius: 8px;
border-left: 4px solid var(--success);
}
.alert-success {
background-color: var(--section-bg);
color: var(--success);
border-color: var(--success);
}
.link-container {
display: flex;
gap: 10px;
margin: 15px 0;
}
.link-container input {
flex: 1;
padding: 10px;
border: 2px solid var(--border-color);
border-radius: 4px;
font-family: monospace;
background: var(--section-bg);
color: var(--text-color);
}
.copy-btn {
padding: 10px 15px;
background: var(--highlight);
color: white;
border: none;
border-radius: 4px;
cursor: pointer;
}
.push-form {
background: var(--section-bg);
padding: 30px;
border-radius: 8px;
margin: 20px 0;
border: 1px solid var(--border-color);
}
.form-group {
margin-bottom: 20px;
}
.form-group label {
display: block;
margin-bottom: 8px;
font-weight: bold;
color: var(--text-color);
}
.form-group textarea {
width: 100%;
min-height: 120px;
padding: 12px;
border: 2px solid var(--border-color);
border-radius: 4px;
font-family: monospace;
resize: vertical;
background: var(--section-bg);
color: var(--text-color);
}
.form-row {
display: grid;
grid-template-columns: 1fr 1fr;
gap: 20px;
}
.form-group input[type="range"] {
width: 100%;
margin: 10px 0;
}
.range-display {
display: flex;
justify-content: space-between;
align-items: center;
margin-top: 5px;
}
.range-display span {
font-weight: bold;
color: var(--highlight);
}
.checkbox-group {
display: flex;
flex-direction: column;
gap: 15px;
}
.checkbox-label {
display: flex;
align-items: flex-start;
gap: 10px;
cursor: pointer;
}
.checkbox-label input[type="checkbox"] {
margin-top: 2px;
}
.checkbox-label small {
display: block;
color: #aaa;
margin-top: 4px;
}
.btn {
display: inline-block;
padding: 12px 24px;
border: none;
border-radius: 4px;
cursor: pointer;
text-decoration: none;
font-weight: bold;
transition: all 0.3s ease;
}
.btn-primary {
background: var(--highlight);
color: white;
}
.btn-primary:hover {
background: #2a4c6c;
}
.btn-secondary {
background: #6c757d;
color: white;
}
.btn-large {
padding: 15px 30px;
font-size: 18px;
width: 100%;
}
.info-section {
background: var(--section-bg);
padding: 25px;
border-radius: 8px;
margin: 20px 0;
border: 1px solid var(--border-color);
}
.info-section h3 {
margin-top: 0;
color: var(--text-color);
}
.info-section ul {
list-style: none;
padding: 0;
}
.info-section li {
padding: 8px 0;
border-bottom: 1px solid var(--border-color);
color: var(--text-color);
}
.info-section li:last-child {
border-bottom: none;
}
.actions {
margin-top: 20px;
text-align: center;
}
/* History Section Styles */
.history-section {
margin-top: 40px;
background: var(--section-bg);
border-radius: 8px;
border: 1px solid var(--border-color);
overflow: hidden;
}
.history-header {
background: var(--bg-color);
padding: 20px;
border-bottom: 1px solid var(--border-color);
display: flex;
justify-content: space-between;
align-items: center;
}
.history-header h2 {
margin: 0;
color: var(--text-color);
}
.history-controls {
display: flex;
gap: 10px;
}
.history-stats {
padding: 15px 20px;
background: var(--bg-color);
border-bottom: 1px solid var(--border-color);
display: flex;
gap: 15px;
}
.stat-badge {
background: var(--section-bg);
padding: 6px 12px;
border-radius: 4px;
border: 1px solid var(--border-color);
font-size: 14px;
font-weight: bold;
color: var(--text-color);
}
.stat-badge.active {
background: var(--success);
color: white;
border-color: var(--success);
}
.stat-badge.expired {
background: var(--danger);
color: white;
border-color: var(--danger);
}
.history-table-container {
overflow-x: auto;
max-width: 100%;
}
.history-table {
width: 100%;
border-collapse: collapse;
font-size: 13px;
min-width: 600px;
}
.history-table th {
background: var(--bg-color);
padding: 10px 6px;
text-align: left;
font-weight: bold;
color: var(--text-color);
border-bottom: 2px solid var(--border-color);
white-space: nowrap;
font-size: 12px;
}
.history-table td {
padding: 10px 6px;
border-bottom: 1px solid var(--border-color);
vertical-align: middle;
color: var(--text-color);
font-size: 12px;
}
.history-table tr.expired {
background: var(--bg-color);
opacity: 0.7;
}
.history-table tr:hover:not(.empty-row) {
background: var(--section-bg);
}
.empty-row td {
text-align: center;
padding: 40px 20px;
color: var(--muted-color);
font-style: italic;
}
.date-cell {
white-space: nowrap;
color: var(--muted-color);
min-width: 110px;
font-size: 11px;
}
.views-cell {
text-align: center;
font-weight: bold;
min-width: 60px;
font-size: 11px;
}
.notes-cell {
max-width: 150px;
font-size: 11px;
word-break: break-word;
}
.status-cell {
text-align: center;
min-width: 80px;
}
.status-badge {
padding: 3px 6px;
border-radius: 4px;
font-size: 10px;
font-weight: bold;
white-space: nowrap;
}
.status-badge.active {
background: var(--success);
color: white;
}
.status-badge.expired {
background: var(--danger);
color: white;
}
.status-badge.deleted {
background: #6c757d;
color: white;
}
.actions-cell {
text-align: center;
white-space: nowrap;
min-width: 140px;
}
.btn-xs {
padding: 3px 6px;
font-size: 10px;
margin: 0 1px;
border-radius: 3px;
}
.expired-text {
color: var(--muted-color);
font-size: 12px;
font-style: italic;
}
@media (max-width: 768px) {
.form-row {
grid-template-columns: 1fr;
}
.link-container {
flex-direction: column;
}
.history-header {
flex-direction: column;
gap: 15px;
align-items: flex-start;
}
.history-stats {
flex-wrap: wrap;
gap: 10px;
}
.history-table {
font-size: 10px;
min-width: 500px;
}
.history-table th,
.history-table td {
padding: 6px 3px;
}
.notes-cell {
max-width: 100px;
}
.date-cell {
font-size: 9px;
min-width: 90px;
}
.actions-cell {
min-width: 120px;
}
.btn-xs {
padding: 2px 4px;
font-size: 9px;
}
}
</style>
{{end}}
{{define "content"}}
<div class="container">
<h1>🔐 Password Pusher</h1>
<p>Share sensitive text securely with automatic expiration and view limits.</p>
{{if .Success}}
<div class="alert alert-success">
<h3>✅ Secure Link Created!</h3>
<p>Your text has been encrypted and stored securely. Share this link:</p>
<div class="link-container">
<input type="text" id="pushUrl" value="{{.PushURL}}" readonly onclick="this.select()">
<button onclick="copyToClipboard()" class="copy-btn">📋 Copy</button>
</div>
<p><small>🕒 Expires: {{.ExpiresAt}} | 🆔 ID: {{.ID}}</small></p>
<p><strong>⚠️ Important:</strong> This link will only work once if auto-delete is enabled!</p>
<a href="/pwpush" class="btn btn-primary">Create Another Link</a>
</div>
{{else}}
<form id="pushForm" method="post" class="push-form">
{{if .CSRFToken}}
<input type="hidden" name="csrf_token" value="{{.CSRFToken}}">
{{end}}
<div class="form-group">
<label for="text">📝 Text to Share:</label>
<textarea name="text" id="text" placeholder="Enter your password, secret, or sensitive text here..." required></textarea>
<small>Enter any sensitive information you want to share securely.</small>
</div>
<div class="form-group">
<label for="protection_password">🔑 Password Protection (Optional):</label>
<input type="password" name="password" id="protection_password"
placeholder="Leave empty for no password protection"
style="width: 75%; padding: 15px 20px; border: 2px solid var(--border-color);
border-radius: 8px; background-color: var(--section-bg); color: var(--text-color);
font-size: 13px; font-family: monospace; margin-top: 5px;"><br>
<small>If set, viewers must enter this password to access the content. This bypasses the click-to-reveal feature.</small>
</div>
<div class="form-row">
<div class="form-group">
<label for="expiry_days">⏰ Expires After:</label>
<input type="range" name="expiry_days" id="expiry_days" min="1" max="90" value="7"
oninput="updateExpiryDisplay(this.value)">
<div class="range-display">
<span id="expiryDisplay">7 days</span>
<small>Max: 3 months</small>
</div>
</div>
<div class="form-group">
<label for="max_views">👁️ Maximum Views:</label>
<input type="range" name="max_views" id="max_views" min="1" max="100" value="10"
oninput="updateViewsDisplay(this.value)">
<div class="range-display">
<span id="viewsDisplay">10 views</span>
<small>Max: 100 views</small>
</div>
</div>
</div>
<div class="form-group">
<div class="checkbox-group">
<label class="checkbox-label">
<input type="checkbox" name="require_click" checked>
<span class="checkmark"></span>
🛡️ Require click to reveal (recommended)
<small>Hides content from web crawlers and requires user interaction</small>
</label>
<label class="checkbox-label">
<input type="checkbox" name="auto_delete">
<span class="checkmark"></span>
🗑️ Allow manual deletion after viewing
<small>Adds a delete button when content is viewed (viewer can choose to delete)</small>
</label>
<label class="checkbox-label">
<input type="checkbox" name="track_history" id="track_history">
<span class="checkmark"></span>
📚 Save to my history
<small>Keep a record of your created links (stored in browser)</small>
</label>
</div>
</div>
<button type="submit" class="btn btn-primary btn-large">
🔒 Create Secure Link
</button>
</form>
<div class="info-section">
<h3>🔒 How it works:</h3>
<ul>
<li><strong>Encryption:</strong> Your text is encrypted before storage</li>
<li><strong>Automatic Expiry:</strong> Links expire after set time or view limit</li>
<li><strong>One-time Use:</strong> Optional auto-delete after viewing</li>
<li><strong>No Registration:</strong> No account required</li>
<li><strong>Browser History:</strong> Optionally track your links locally</li>
</ul>
</div>
{{end}}
<!-- History Section -->
<div class="history-section">
<div class="history-header">
<h2>📚 My Recent Links</h2>
<div class="history-controls">
<button onclick="refreshHistory()" class="btn btn-secondary btn-sm">🔄 Refresh</button>
<button onclick="clearHistory()" class="btn btn-danger btn-sm">🗑️ Clear All</button>
</div>
</div>
<div id="historyContainer">
<div class="history-stats">
<span class="stat-badge">Total: <span id="totalCount">0</span></span>
<span class="stat-badge active">Active: <span id="activeCount">0</span></span>
<span class="stat-badge expired">Expired: <span id="expiredCount">0</span></span>
</div>
<div class="history-table-container">
<table id="historyTable" class="history-table">
<thead>
<tr>
<th>📅 Created</th>
<th>⏰ Expires</th>
<th><EFBFBD> Views</th>
<th>📝 Local Notes</th>
<th>🔗 Status</th>
<th>⚡ Actions</th>
</tr>
</thead>
<tbody id="historyTableBody">
<tr class="empty-row">
<td colspan="6" class="empty-message">
📭 No history found. Enable "Save to my history" when creating links.
</td>
</tr>
</tbody>
</table>
</div>
</div>
</div>
</div>
<script>
function updateExpiryDisplay(days) {
const display = document.getElementById('expiryDisplay');
if (days == 1) {
display.textContent = '1 day';
} else if (days <= 7) {
display.textContent = days + ' days';
} else if (days <= 30) {
const weeks = Math.floor(days / 7);
const remainingDays = days % 7;
if (remainingDays === 0) {
display.textContent = weeks + (weeks === 1 ? ' week' : ' weeks');
} else {
display.textContent = weeks + 'w ' + remainingDays + 'd';
}
} else {
const months = Math.floor(days / 30);
const remainingDays = days % 30;
if (remainingDays === 0) {
display.textContent = months + (months === 1 ? ' month' : ' months');
} else {
display.textContent = months + 'm ' + remainingDays + 'd';
}
}
}
function updateViewsDisplay(views) {
const display = document.getElementById('viewsDisplay');
display.textContent = views + (views === '1' ? ' view' : ' views');
}
function copyToClipboard() {
const urlInput = document.getElementById('pushUrl');
urlInput.select();
document.execCommand('copy');
const btn = document.querySelector('.copy-btn');
const originalText = btn.textContent;
btn.textContent = '✅ Copied!';
btn.style.background = '#4caf50';
setTimeout(() => {
btn.textContent = originalText;
btn.style.background = '';
}, 2000);
}
// Save settings to cookies when form is submitted
document.getElementById('pushForm').addEventListener('submit', function() {
const expiryDays = document.getElementById('expiry_days').value;
const maxViews = document.getElementById('max_views').value;
const requireClick = document.querySelector('input[name="require_click"]').checked;
const autoDelete = document.querySelector('input[name="auto_delete"]').checked;
const trackHistory = document.querySelector('input[name="track_history"]').checked;
setCookie('pwpush_expiry_days', expiryDays, 30);
setCookie('pwpush_max_views', maxViews, 30);
setCookie('pwpush_require_click', requireClick, 30);
setCookie('pwpush_auto_delete', autoDelete, 30);
setCookie('pwpush_track_history', trackHistory, 30);
});
// History functionality
function refreshHistory() {
// Show loading state
const refreshBtn = document.querySelector('button[onclick="refreshHistory()"]');
const originalText = refreshBtn.textContent;
refreshBtn.textContent = '🔄 Validating...';
refreshBtn.disabled = true;
setTimeout(() => {
loadHistory();
refreshBtn.textContent = originalText;
refreshBtn.disabled = false;
}, 100);
}
function validateLinksWithServer(history) {
// Only validate links that are not already marked as expired/deleted
const activeLinks = history.filter(item => !item.isDeleted && new Date(item.expiresAt) > new Date());
if (activeLinks.length === 0) {
return Promise.resolve(history); // No active links to validate
}
const ids = activeLinks.map(item => item.id);
return fetch('/pwpush/api/status/', {
method: 'POST',
headers: {
'Content-Type': 'application/json',
},
body: JSON.stringify({ ids: ids })
})
.then(response => {
if (!response.ok) {
throw new Error('Failed to validate links');
}
return response.json();
})
.then(statuses => {
// Update history items with server status
const statusMap = {};
statuses.forEach(status => {
statusMap[status.id] = status;
});
return history.map(item => {
const serverStatus = statusMap[item.id];
if (serverStatus) {
// Update with server data
item.exists = serverStatus.exists;
item.isDeleted = serverStatus.is_deleted;
item.viewCount = serverStatus.current_views;
item.maxViews = serverStatus.max_views;
// Mark as expired if server says so
if (serverStatus.is_expired || !serverStatus.exists) {
item.isExpired = true;
}
// If link doesn't exist on server, mark for removal
if (!serverStatus.exists) {
item.shouldRemove = true;
}
}
return item;
}).filter(item => !item.shouldRemove); // Remove non-existent links
})
.catch(error => {
console.warn('Failed to validate links with server:', error);
return history; // Return original history if validation fails
});
}
function loadHistory() {
let history = getHistoryFromCookie();
// Only validate if "track history" is enabled
const trackHistory = getCookie('pwpush_track_history');
if (trackHistory === 'true' && history.length > 0) {
// Validate with server and update display
validateLinksWithServer(history).then(validatedHistory => {
// Save updated history back to cookies
if (validatedHistory.length !== history.length) {
saveHistoryToCookie(validatedHistory);
history = validatedHistory;
}
displayHistory(history);
});
} else {
displayHistory(history);
}
}
function displayHistory(history) {
const tbody = document.getElementById('historyTableBody');
const emptyRow = tbody.querySelector('.empty-row');
if (history.length === 0) {
if (emptyRow) emptyRow.style.display = '';
updateStats(0, 0, 0);
return;
}
if (emptyRow) emptyRow.style.display = 'none';
// Clear existing rows except empty row
const existingRows = tbody.querySelectorAll('tr:not(.empty-row)');
existingRows.forEach(row => row.remove());
let activeCount = 0;
let expiredCount = 0;
history.forEach(item => {
const isExpired = item.isExpired || item.isDeleted || new Date(item.expiresAt) < new Date();
if (isExpired) expiredCount++;
else activeCount++;
const row = createHistoryRow(item, isExpired);
tbody.appendChild(row);
});
updateStats(history.length, activeCount, expiredCount);
}
function createHistoryRow(item, isExpired) {
const row = document.createElement('tr');
row.className = isExpired ? 'expired' : 'active';
// Determine status text and actions based on server state
let statusText = '✅ Active';
let statusClass = 'active';
let actions = '';
if (item.isDeleted) {
statusText = '🗑️ Deleted';
statusClass = 'deleted';
actions = '<span class="expired-text">Deleted on server</span>';
} else if (isExpired) {
statusText = '❌ Expired';
statusClass = 'expired';
actions = '<span class="expired-text">Expired</span>';
} else {
actions = `<button onclick="copyLink('${item.url}')" class="btn btn-secondary btn-xs" title="Copy Link">📋</button>
<a href="${item.url}" class="btn btn-primary btn-xs" target="_blank" title="View">👁️</a>
<button onclick="editNotes('${item.id}')" class="btn btn-secondary btn-xs" title="Edit Notes">✏️</button>`;
}
// Always show remove button for cleaning up history
actions += `<button onclick="removeFromHistory('${item.id}')" class="btn btn-danger btn-xs" title="Remove">🗑️</button>`;
row.innerHTML = `
<td class="date-cell">
${formatDate(item.createdAt)}
</td>
<td class="date-cell">
${formatDate(item.expiresAt)}
</td>
<td class="views-cell">
${item.viewCount || 0}/${item.maxViews}
</td>
<td class="notes-cell">
<span class="notes-text">${item.notes ? item.notes.substring(0, 30) + (item.notes.length > 30 ? '...' : '') : '-'}</span>
</td>
<td class="status-cell">
<span class="status-badge ${statusClass}">
${statusText}
</span>
</td>
<td class="actions-cell">
${actions}
</td>
`;
return row;
}
function updateStats(total, active, expired) {
document.getElementById('totalCount').textContent = total;
document.getElementById('activeCount').textContent = active;
document.getElementById('expiredCount').textContent = expired;
}
function formatDate(dateString) {
const date = new Date(dateString);
return date.toLocaleDateString() + ' ' + date.toLocaleTimeString([], {hour: '2-digit', minute:'2-digit'});
}
function copyLink(url) {
const textArea = document.createElement('textarea');
textArea.value = url;
document.body.appendChild(textArea);
textArea.select();
document.execCommand('copy');
document.body.removeChild(textArea);
// Show success feedback
const btn = event.target;
const originalText = btn.textContent;
btn.textContent = '✅';
btn.style.background = '#4caf50';
setTimeout(() => {
btn.textContent = originalText;
btn.style.background = '';
}, 1500);
}
function removeFromHistory(pushId) {
if (confirm('Remove this item from your history?')) {
const history = getHistoryFromCookie();
const updatedHistory = history.filter(h => h.id !== pushId);
saveHistoryToCookie(updatedHistory);
loadHistory();
}
}
function editNotes(pushId) {
const history = getHistoryFromCookie();
const item = history.find(h => h.id === pushId);
if (!item) return;
const currentNotes = item.notes || '';
const newNotes = prompt('Add notes for this link (for your reference only):', currentNotes);
if (newNotes !== null) { // User didn't cancel
item.notes = newNotes;
saveHistoryToCookie(history);
loadHistory();
}
}
function clearHistory() {
if (confirm('Clear all history? This cannot be undone.')) {
// Show loading state
const clearBtn = document.querySelector('button[onclick="clearHistory()"]');
const originalText = clearBtn.textContent;
clearBtn.textContent = '🗑️ Clearing...';
clearBtn.disabled = true;
// Clear the cookie
document.cookie = "pwpush_history=; expires=Thu, 01 Jan 1970 00:00:00 UTC; path=/;";
// Refresh the display and restore button
setTimeout(() => {
loadHistory(); // Refresh the display to show cleared state
clearBtn.textContent = '✅ Cleared!';
// Restore original text after showing success
setTimeout(() => {
clearBtn.textContent = originalText;
clearBtn.disabled = false;
}, 1500);
}, 100);
}
}
function getHistoryFromCookie() {
const cookie = document.cookie
.split('; ')
.find(row => row.startsWith('pwpush_history='));
if (!cookie) return [];
try {
return JSON.parse(decodeURIComponent(cookie.split('=')[1]));
} catch (e) {
return [];
}
}
function saveHistoryToCookie(history) {
const expires = new Date();
expires.setTime(expires.getTime() + (30 * 24 * 60 * 60 * 1000)); // 30 days
document.cookie = `pwpush_history=${encodeURIComponent(JSON.stringify(history))};expires=${expires.toUTCString()};path=/`;
}
function getCookie(name) {
const value = "; " + document.cookie;
const parts = value.split("; " + name + "=");
if (parts.length === 2) return parts.pop().split(";").shift();
return null;
}
function setCookie(name, value, days) {
const expires = new Date();
expires.setTime(expires.getTime() + (days * 24 * 60 * 60 * 1000));
document.cookie = name + "=" + value + ";expires=" + expires.toUTCString() + ";path=/";
}
// Load history on page load
document.addEventListener('DOMContentLoaded', function() {
loadHistory();
// Check if this is a success page with a new link created
const successData = document.querySelector('meta[name="success-data"]');
if (successData) {
const trackHistory = getCookie('pwpush_track_history');
if (trackHistory === 'true') {
// Add the new link to history
const data = JSON.parse(successData.content);
const newItem = {
id: data.id,
url: data.url,
createdAt: new Date().toISOString(),
expiresAt: data.expiresAt,
maxViews: parseInt(getCookie('pwpush_max_views')) || 10,
viewCount: 0,
previewText: 'Content hidden for security'
};
let history = getHistoryFromCookie();
history.unshift(newItem); // Add to beginning
// Keep only last 50 items
if (history.length > 50) {
history = history.slice(0, 50);
}
saveHistoryToCookie(history);
loadHistory(); // Refresh the display
}
}
// Load saved preferences
const savedExpiry = getCookie('pwpush_expiry_days');
const savedViews = getCookie('pwpush_max_views');
const savedRequireClick = getCookie('pwpush_require_click');
const savedAutoDelete = getCookie('pwpush_auto_delete');
const savedTrackHistory = getCookie('pwpush_track_history');
if (savedExpiry) {
document.getElementById('expiry_days').value = savedExpiry;
updateExpiryDisplay(savedExpiry);
}
if (savedViews) {
document.getElementById('max_views').value = savedViews;
updateViewsDisplay(savedViews);
}
if (savedRequireClick !== null) {
document.querySelector('input[name="require_click"]').checked = savedRequireClick === 'true';
}
if (savedAutoDelete !== null) {
document.querySelector('input[name="auto_delete"]').checked = savedAutoDelete === 'true';
}
if (savedTrackHistory !== null) {
document.querySelector('input[name="track_history"]').checked = savedTrackHistory === 'true';
}
});
</script>
{{end}}