clearance
This commit is contained in:
parent
17bb747542
commit
e46dec38ca
@ -1,110 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Binary file viewer{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="container mt-4">
|
|
||||||
<div class="card shadow-sm">
|
|
||||||
<div class="card-body">
|
|
||||||
<h1 class="mb-3">Viewing File: {{ filename }}</h1>
|
|
||||||
<p class="text-muted">Tipo MIME: {{ mime_type }}</p>
|
|
||||||
|
|
||||||
<div class="row mb-4">
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>File Info</h4>
|
|
||||||
<ul class="list-group list-group-flush">
|
|
||||||
<li class="list-group-item"><strong>File Name:</strong> {{ filename }}</li>
|
|
||||||
<li class="list-group-item"><strong>Size:</strong> {{ size }} bytes</li>
|
|
||||||
<li class="list-group-item"><strong>Uploaded by:</strong> {{ owner.username }}</li>
|
|
||||||
<li class="list-group-item"><strong>Upload Date:</strong> {{ paste.created_at.strftime('%Y-%m-%d %H:%M:%S') }}</li>
|
|
||||||
</ul>
|
|
||||||
</div>
|
|
||||||
<div class="col-md-6">
|
|
||||||
<h4>Acciones</h4>
|
|
||||||
<div class="d-flex flex-column">
|
|
||||||
<a href="{{ url_for('download_paste', id=paste.id) }}" class="btn btn-success mb-2">
|
|
||||||
<i class="fas fa-download me-2"></i> Descargar Archivo
|
|
||||||
</a>
|
|
||||||
{% if 'admin' in session %}
|
|
||||||
<button type="button" class="btn btn-danger" data-bs-toggle="modal" data-bs-target="#deleteModal" aria-label="Delete Paste">
|
|
||||||
<i class="fas fa-trash-alt me-2"></i> Delete Paste
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="card">
|
|
||||||
<div class="card-body text-center">
|
|
||||||
<h5 class="card-title">Download from smartphone</h5>
|
|
||||||
<p class="card-text">Scan this code from your mobile device:</p>
|
|
||||||
<div id="qrcode" class="my-3 mx-auto" style="width:200px; height:200px;"></div>
|
|
||||||
<button id="download-qr" class="btn btn-outline-primary mt-2">
|
|
||||||
<i class="fas fa-download me-2"></i> Download QR
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if 'admin' in session %}
|
|
||||||
<div class="modal fade" id="deleteModal" tabindex="-1" aria-labelledby="deleteModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<form action="{{ url_for('admin_delete_paste', paste_id=paste.id) }}" method="POST">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="deleteModalLabel">Confirmar Eliminación</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
¿Are you sure? This action cannot be undone.
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
||||||
<button type="submit" class="btn btn-danger">Delete</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</form>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const pasteId = "{{ paste.id }}";
|
|
||||||
const downloadUrl = "{{ url_for('download_paste', id=paste.id, _external=True) }}";
|
|
||||||
|
|
||||||
const qrCodeContainer = document.getElementById('qrcode');
|
|
||||||
|
|
||||||
new QRCode(qrCodeContainer, {
|
|
||||||
text: downloadUrl,
|
|
||||||
width: 200,
|
|
||||||
height: 200,
|
|
||||||
colorDark : "#000000",
|
|
||||||
colorLight : "#ffffff",
|
|
||||||
correctLevel : QRCode.CorrectLevel.H
|
|
||||||
});
|
|
||||||
|
|
||||||
const downloadQrButton = document.getElementById('download-qr');
|
|
||||||
downloadQrButton.addEventListener('click', () => {
|
|
||||||
const canvas = qrCodeContainer.querySelector('canvas');
|
|
||||||
if (canvas) {
|
|
||||||
const pngUrl = canvas.toDataURL("image/png").replace("image/png", "image/octet-stream");
|
|
||||||
const downloadLink = document.createElement('a');
|
|
||||||
downloadLink.href = pngUrl;
|
|
||||||
downloadLink.download = `qr_code_paste_${pasteId}.png`;
|
|
||||||
document.body.appendChild(downloadLink);
|
|
||||||
downloadLink.click();
|
|
||||||
document.body.removeChild(downloadLink);
|
|
||||||
alert('QR descargado exitosamente!');
|
|
||||||
} else {
|
|
||||||
alert('Error al generar el código QR.');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,73 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Media Viewer{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="container mt-4">
|
|
||||||
<h1 class="text-center">Viewing Media: {{ filename }}</h1>
|
|
||||||
<p class="text-muted text-center">MIME Type: {{ mime_type }}</p>
|
|
||||||
|
|
||||||
<div class="media-container text-center">
|
|
||||||
{% if mime_type.startswith("image/") %}
|
|
||||||
<img src="{{ url_for('get_file', filename=filename) }}" alt="Image" class="img-fluid" />
|
|
||||||
{% elif mime_type.startswith("video/") %}
|
|
||||||
<video controls class="w-100">
|
|
||||||
<source src="{{ url_for('get_file', filename=filename) }}" type="{{ mime_type }}">
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
{% elif mime_type.startswith("audio/") %}
|
|
||||||
<audio controls class="w-100">
|
|
||||||
<source src="{{ url_for('get_file', filename=filename) }}" type="{{ mime_type }}">
|
|
||||||
Your browser does not support the audio element.
|
|
||||||
</audio>
|
|
||||||
{% elif mime_type == "application/pdf" %}
|
|
||||||
<embed src="{{ url_for('get_file', filename=filename) }}" type="{{ mime_type }}" width="100%" height="600px">
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-center mt-4">
|
|
||||||
<button class="btn btn-primary me-2" onclick="toggleMetadata()">Toggle Metadata</button>
|
|
||||||
<a href="{{ url_for('download_paste', id=paste_id) }}" class="btn btn-success">📥 Download</a>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="metadata mt-4">
|
|
||||||
<div id="metadata-content" class="metadata-content" style="display: none;">
|
|
||||||
<table class="table table-bordered table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Property</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% if metadata %}
|
|
||||||
{% for track in metadata %}
|
|
||||||
{% for key, value in track.items() %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ key }}</td>
|
|
||||||
<td>{{ value }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">No metadata available for this file.</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<script>
|
|
||||||
function toggleMetadata() {
|
|
||||||
const content = document.getElementById("metadata-content");
|
|
||||||
if (content.style.display === "none") {
|
|
||||||
content.style.display = "block";
|
|
||||||
} else {
|
|
||||||
content.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,139 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Media Viewer{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="container mt-4">
|
|
||||||
<h1 class="text-center">Viewing Media: {{ filename }}</h1>
|
|
||||||
<p class="text-muted text-center">MIME Type: {{ mime_type }}</p>
|
|
||||||
|
|
||||||
<div class="media-container text-center">
|
|
||||||
{% if mime_type.startswith("image/") %}
|
|
||||||
<img src="{{ url_for('get_file', filename=filename) }}" alt="Image" class="img-fluid" />
|
|
||||||
{% elif mime_type.startswith("video/") %}
|
|
||||||
<video controls class="w-100">
|
|
||||||
<source src="{{ url_for('get_file', filename=filename) }}" type="{{ mime_type }}">
|
|
||||||
Your browser does not support the video tag.
|
|
||||||
</video>
|
|
||||||
{% elif mime_type.startswith("audio/") %}
|
|
||||||
<audio controls class="w-100">
|
|
||||||
<source src="{{ url_for('get_file', filename=filename) }}" type="{{ mime_type }}">
|
|
||||||
Your browser does not support the audio element.
|
|
||||||
</audio>
|
|
||||||
{% elif mime_type == "application/pdf" %}
|
|
||||||
<embed src="{{ url_for('get_file', filename=filename) }}" type="{{ mime_type }}" width="100%" height="600px">
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-center mt-4">
|
|
||||||
<button class="btn btn-primary me-2" onclick="toggleMetadata()">Toggle Metadata</button>
|
|
||||||
<a href="{{ url_for('download_paste', id=paste_id) }}" class="btn btn-primary me-2">📥 Download</a>
|
|
||||||
<a href="{{ url_for('get_file', filename=filename) }}" class="btn btn-primary me-2" target="_blank">🌐 View Raw</a>
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
<!-- Botón de favoritos, con clase "btn btn-sm btn-primary" para mantener la consistencia -->
|
|
||||||
<button id="favorite-button" class="btn btn-sm btn-primary">
|
|
||||||
❤️ Add to Favorites
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="metadata mt-4">
|
|
||||||
<div id="metadata-content" class="metadata-content" style="display: none;">
|
|
||||||
<table class="table table-bordered table-striped">
|
|
||||||
<thead>
|
|
||||||
<tr>
|
|
||||||
<th>Property</th>
|
|
||||||
<th>Value</th>
|
|
||||||
</tr>
|
|
||||||
</thead>
|
|
||||||
<tbody>
|
|
||||||
{% if metadata %}
|
|
||||||
{% for track in metadata %}
|
|
||||||
{% for key, value in track.items() %}
|
|
||||||
<tr>
|
|
||||||
<td>{{ key }}</td>
|
|
||||||
<td>{{ value }}</td>
|
|
||||||
</tr>
|
|
||||||
{% endfor %}
|
|
||||||
{% endfor %}
|
|
||||||
{% else %}
|
|
||||||
<tr>
|
|
||||||
<td colspan="2">No metadata available for this file.</td>
|
|
||||||
</tr>
|
|
||||||
{% endif %}
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Contenedor para el Toast (puede ir en base.html o aquí) -->
|
|
||||||
<div class="position-fixed bottom-0 end-0 p-3" style="z-index: 1100">
|
|
||||||
<div id="liveToast" class="toast align-items-center text-white bg-primary border-0" role="alert" aria-live="assertive" aria-atomic="true" style="display: none;">
|
|
||||||
<div class="d-flex">
|
|
||||||
<div class="toast-body">
|
|
||||||
<!-- Mensaje dinámico -->
|
|
||||||
</div>
|
|
||||||
<button type="button" class="btn-close btn-close-white me-2 m-auto" data-bs-dismiss="toast" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
function toggleMetadata() {
|
|
||||||
const content = document.getElementById("metadata-content");
|
|
||||||
if (content.style.display === "none") {
|
|
||||||
content.style.display = "block";
|
|
||||||
} else {
|
|
||||||
content.style.display = "none";
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Solo configuramos el listener si el usuario está autenticado
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
document.addEventListener('DOMContentLoaded', () => {
|
|
||||||
const favoriteButton = document.getElementById('favorite-button');
|
|
||||||
if (favoriteButton) {
|
|
||||||
favoriteButton.addEventListener('click', function() {
|
|
||||||
fetch(`/paste/{{ paste_id }}/favorite`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Authorization': 'Bearer {{ token }}'
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.then(response => {
|
|
||||||
if (!response.ok) {
|
|
||||||
throw new Error('Failed to toggle favorite');
|
|
||||||
}
|
|
||||||
return response.json();
|
|
||||||
})
|
|
||||||
.then(data => {
|
|
||||||
const message = data.message || 'Action completed!';
|
|
||||||
showToast(message, 'bg-success');
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error:', error);
|
|
||||||
showToast('Error adding to favorites.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Función para mostrar el toast
|
|
||||||
function showToast(message, bgColor = 'bg-primary') {
|
|
||||||
const toastElement = document.getElementById('liveToast');
|
|
||||||
const toastBody = toastElement.querySelector('.toast-body');
|
|
||||||
|
|
||||||
toastBody.textContent = message;
|
|
||||||
toastElement.className = `toast align-items-center text-white ${bgColor} border-0`;
|
|
||||||
toastElement.style.display = 'block'; // Mostrar el contenedor
|
|
||||||
|
|
||||||
const toast = new bootstrap.Toast(toastElement);
|
|
||||||
toast.show();
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
{% block footer %}
|
|
||||||
{{ super() }} <!-- Esto conserva el contenido original del footer definido en base.html -->
|
|
||||||
{% endblock %}
|
|
@ -1,198 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Paste {{ paste.id }}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
<div class="container mt-4">
|
|
||||||
{% if paste.owner_id == current_user.id %}
|
|
||||||
<div class="modal fade" id="shareModal" tabindex="-1" aria-labelledby="shareModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Share Paste</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="mb-3">
|
|
||||||
<input type="text" id="share-username" placeholder="Username" class="form-control">
|
|
||||||
<div id="user-suggestions" class="list-group position-absolute d-none" style="z-index: 1050;"></div>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input type="checkbox" id="share-can-edit" class="form-check-input" checked>
|
|
||||||
<label class="form-check-label" for="share-can-edit">Allow Edit</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" id="share-submit" class="btn btn-success">Share Paste</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap">
|
|
||||||
<h1 class="mb-0">Paste {{ paste.id }}</h1>
|
|
||||||
<div class="d-flex flex-wrap gap-2">
|
|
||||||
{% if paste.owner_id == current_user.id %}
|
|
||||||
<button id="share-button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#shareModal" title="Share Paste">
|
|
||||||
<i class="fas fa-share-alt"></i>
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
<button id="favorite-button" class="btn btn-sm btn-secondary" title="Toggle Favorite">
|
|
||||||
<i class="fas fa-heart"></i>
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if can_edit %}
|
|
||||||
<a id="edit-button" href="{{ url_for('edit_paste_web', id=paste.id) }}" class="btn btn-sm btn-warning" title="Edit Paste">
|
|
||||||
<i class="fas fa-edit"></i>
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<button id="copy-url-button" class="btn btn-sm btn-secondary" title="Copy URL">
|
|
||||||
<i class="fas fa-link"></i>
|
|
||||||
</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 🔥 Botón de IA fuera del grupo de botones -->
|
|
||||||
<button id="ai-generate-code" class="btn btn-sm btn-outline-primary magic-btn" title="AI Suggestions">
|
|
||||||
✨
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<!-- Código Mejorado por IA -->
|
|
||||||
<div id="generated-code-container" class="mt-3 d-none">
|
|
||||||
<h5 class="text-primary">💻 AI-Enhanced Code:</h5>
|
|
||||||
<div id="generated-code-box">
|
|
||||||
<pre id="generated-code"></pre>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<style>
|
|
||||||
/* Botón IA como icono */
|
|
||||||
.magic-btn {
|
|
||||||
font-size: 18px;
|
|
||||||
padding: 6px 10px;
|
|
||||||
border-radius: 50%;
|
|
||||||
transition: background 0.2s ease-in-out;
|
|
||||||
}
|
|
||||||
|
|
||||||
.magic-btn:hover {
|
|
||||||
background-color: #007bff;
|
|
||||||
color: white;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Contenedor de código */
|
|
||||||
#generated-code-box {
|
|
||||||
background-color: #1e1e1e;
|
|
||||||
color: #c9d1d9;
|
|
||||||
font-family: "Fira Code", monospace;
|
|
||||||
font-size: 14px;
|
|
||||||
border: 1px solid #444;
|
|
||||||
padding: 10px;
|
|
||||||
max-height: 300px;
|
|
||||||
overflow-y: auto;
|
|
||||||
border-radius: 8px;
|
|
||||||
box-shadow: 0px 4px 10px rgba(0, 0, 0, 0.2);
|
|
||||||
white-space: pre-wrap;
|
|
||||||
word-wrap: break-word;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|
||||||
<p class="text-muted small">
|
|
||||||
{% if paste.filename and '.' in paste.filename %}
|
|
||||||
<strong>Extension:</strong> {{ paste.filename.split('.')[-1] }} |
|
|
||||||
{% endif %}
|
|
||||||
<strong>MIME Type:</strong> {{ paste.content_type }} |
|
|
||||||
<strong>Language:</strong> {{ paste.language }} |
|
|
||||||
<strong>Size:</strong>
|
|
||||||
{% if paste.size < 1024 %}
|
|
||||||
{{ paste.size }} bytes
|
|
||||||
{% elif paste.size < 1024 * 1024 %}
|
|
||||||
{{ '%.2f' | format(paste.size / 1024) }} KB
|
|
||||||
{% else %}
|
|
||||||
{{ '%.2f' | format(paste.size / (1024 * 1024)) }} MB
|
|
||||||
{% endif %}
|
|
||||||
</p>
|
|
||||||
|
|
||||||
<div class="mb-3">
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2 flex-wrap">
|
|
||||||
<div class="mb-2">
|
|
||||||
{% if not is_markdown %}
|
|
||||||
<button id="copy-button" class="btn btn-sm btn-secondary me-2" title="Copy Content">
|
|
||||||
<i class="fas fa-clipboard"></i>
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
<a class="btn btn-sm btn-primary" href="{{ url_for('download_paste', id=paste.id) }}" download title="Download Paste">
|
|
||||||
<i class="fas fa-download"></i>
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<div>
|
|
||||||
<label for="pygments-style" class="form-label me-2 mb-0">Style:</label>
|
|
||||||
<select id="pygments-style" class="form-select form-select-sm style-selector d-inline-block w-auto">
|
|
||||||
{% for style in pygments_styles %}
|
|
||||||
<option value="{{ style }}" {% if style == default_pygments_style %}selected{% endif %}>{{ style.replace('-', ' ').capitalize() }}</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
{% if is_markdown %}
|
|
||||||
<div class="markdown-body">{{ md_html_code|safe }}</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="highlight"><code class="language-{{ paste.language|lower }}">{{ html_code|safe }}</code></div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<p class="mt-3">View the raw version <a href="{{ url_for('get_paste_raw', id=paste.id) }}">here</a>.</p>
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
{{ super() }}
|
|
||||||
<script src="{{ url_for('static', filename='js/share-paste.js') }}" defer></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/share-autocomplete.js') }}" defer></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/copy-paste.js') }}" defer></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/pygments-style.js') }}" defer></script>
|
|
||||||
<script src="{{ url_for('static', filename='js/unshare.js') }}" defer></script>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
document.getElementById("ai-generate-code").addEventListener("click", function () {
|
|
||||||
document.getElementById("generated-code").textContent = ""; // Limpiar salida previa
|
|
||||||
document.getElementById("generated-code-container").classList.remove("d-none");
|
|
||||||
|
|
||||||
fetch("{{ url_for('generate_code_from_paste', id=paste.id) }}")
|
|
||||||
.then(response => {
|
|
||||||
const reader = response.body.getReader();
|
|
||||||
const decoder = new TextDecoder();
|
|
||||||
let text = "";
|
|
||||||
const outputElement = document.getElementById("generated-code");
|
|
||||||
|
|
||||||
function readChunk() {
|
|
||||||
reader.read().then(({ done, value }) => {
|
|
||||||
if (done) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let chunkText = decoder.decode(value, { stream: true });
|
|
||||||
|
|
||||||
// Limpiar texto si contiene estructura JSON
|
|
||||||
chunkText = chunkText.replace(/data: \{"id":.*?"choices":\[\{"delta":\{"content":"(.*?)"\}\}\]\}/g, "$1");
|
|
||||||
|
|
||||||
text += chunkText;
|
|
||||||
outputElement.textContent = text;
|
|
||||||
outputElement.scrollTop = outputElement.scrollHeight; // Hacer scroll automático
|
|
||||||
|
|
||||||
readChunk(); // Continuar leyendo los datos
|
|
||||||
});
|
|
||||||
}
|
|
||||||
readChunk();
|
|
||||||
})
|
|
||||||
.catch(error => alert("Error generando código: " + error));
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
@ -1,484 +0,0 @@
|
|||||||
{% extends "base.html" %}
|
|
||||||
|
|
||||||
{% block title %}Paste {{ paste.id }}{% endblock %}
|
|
||||||
|
|
||||||
{% block content %}
|
|
||||||
|
|
||||||
<div class="container mt-4">
|
|
||||||
<!-- Encabezado del Paste -->
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-3 flex-wrap">
|
|
||||||
<h1 class="mb-0">Paste {{ paste.id }}</h1>
|
|
||||||
<!-- Barra de botones -->
|
|
||||||
<div class="d-flex flex-wrap gap-2">
|
|
||||||
{% if paste.owner_id == current_user.id %}
|
|
||||||
<!-- Botón para compartir -->
|
|
||||||
<button id="share-button" class="btn btn-sm btn-primary" data-bs-toggle="modal" data-bs-target="#shareModal">
|
|
||||||
Share
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
<!-- Botón de favoritos -->
|
|
||||||
<button id="favorite-button" class="btn btn-sm btn-secondary">
|
|
||||||
❤️ {% if paste in current_user.favorite_pastes %}Remove from Favorites{% else %}Add to Favorites{% endif %}
|
|
||||||
</button>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Botón para editar (solo si se puede editar) -->
|
|
||||||
{% if can_edit %}
|
|
||||||
<a id="edit-button" href="{{ url_for('edit_paste_web', id=paste.id) }}" class="btn btn-sm btn-warning">
|
|
||||||
Edit Paste
|
|
||||||
</a>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Modal de Compartir Paste (solo si eres el propietario) -->
|
|
||||||
<!-- Modal de Compartir Paste (solo si eres el propietario) -->
|
|
||||||
{% if paste.owner_id == current_user.id %}
|
|
||||||
<div class="modal fade" id="shareModal" tabindex="-1" aria-labelledby="shareModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title">Share Paste</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<div class="mb-3 position-relative">
|
|
||||||
<input type="text"
|
|
||||||
id="share-username"
|
|
||||||
placeholder="Username"
|
|
||||||
class="form-control mb-3"
|
|
||||||
autocomplete="off">
|
|
||||||
<div id="user-suggestions" class="list-group position-absolute d-none" style="z-index: 1050;"></div>
|
|
||||||
</div>
|
|
||||||
<div class="form-check">
|
|
||||||
<input type="checkbox" id="share-can-edit" class="form-check-input" checked>
|
|
||||||
<label class="form-check-label" for="share-can-edit">Allow Edit</label>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<button type="button" id="share-submit" class="btn btn-success">Share Paste</button>
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Close</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Sección principal: contenido del Paste -->
|
|
||||||
<div class="mb-3">
|
|
||||||
<!-- Botones de copiar y descargar -->
|
|
||||||
<div class="d-flex justify-content-between align-items-center mb-2 flex-wrap">
|
|
||||||
<div class="mb-2">
|
|
||||||
{% if not is_markdown %}
|
|
||||||
<button id="copy-button" class="btn btn-sm btn-secondary me-2">📋 Copy</button>
|
|
||||||
{% endif %}
|
|
||||||
<a class="btn btn-sm btn-primary" href="{{ url_for('download_paste', id=paste.id) }}" download>
|
|
||||||
📥 Download
|
|
||||||
</a>
|
|
||||||
</div>
|
|
||||||
<!-- Desplegable de Estilos de Pygments -->
|
|
||||||
<div>
|
|
||||||
<label for="pygments-style" class="form-label me-2 mb-0">Style:</label>
|
|
||||||
<select id="pygments-style" class="form-select form-select-sm style-selector d-inline-block w-auto">
|
|
||||||
{% for style in pygments_styles %}
|
|
||||||
<option value="{{ style }}"
|
|
||||||
{% if style == default_pygments_style %}selected{% endif %}>
|
|
||||||
{{ style.replace('-', ' ').capitalize() }}
|
|
||||||
</option>
|
|
||||||
{% endfor %}
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Mostrar contenido según Markdown o texto plano -->
|
|
||||||
{% if is_markdown %}
|
|
||||||
<div class="markdown-body">
|
|
||||||
{{ md_html_code|safe }}
|
|
||||||
</div>
|
|
||||||
{% else %}
|
|
||||||
<div class="highlight">
|
|
||||||
<code class="language-{{ paste.language|lower }}">{{ html_code|safe }}</code>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<p class="mt-3">
|
|
||||||
View the raw version <a href="{{ url_for('get_paste_raw', id=paste.id) }}">here</a>.
|
|
||||||
</p>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<!-- Botón para ver la lista de usuarios con acceso (oculto por defecto en un collapse) -->
|
|
||||||
{% if current_user.is_authenticated %}
|
|
||||||
<button
|
|
||||||
class="btn btn-sm btn-info mb-2"
|
|
||||||
type="button"
|
|
||||||
data-bs-toggle="collapse"
|
|
||||||
data-bs-target="#sharedWithCollapse"
|
|
||||||
aria-expanded="false"
|
|
||||||
aria-controls="sharedWithCollapse">
|
|
||||||
See users with access
|
|
||||||
</button>
|
|
||||||
|
|
||||||
<div class="collapse" id="sharedWithCollapse">
|
|
||||||
<div class="card card-body">
|
|
||||||
<h5>Shared With:</h5>
|
|
||||||
<ul class="list-group">
|
|
||||||
<ul class="list-group">
|
|
||||||
{% for user, can_edit in shared_with %}
|
|
||||||
<li class="list-group-item d-flex justify-content-between align-items-center">
|
|
||||||
<span>{{ user }}</span>
|
|
||||||
<span>
|
|
||||||
{% if can_edit %}
|
|
||||||
<span class="badge bg-success">Can Edit</span>
|
|
||||||
{% else %}
|
|
||||||
<span class="badge bg-secondary">Read Only</span>
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
<!-- Botón “Unshare” que abrirá el modal -->
|
|
||||||
<button class="btn btn-sm btn-danger ms-2"
|
|
||||||
onclick="showUnshareModal('{{ paste.id }}', '{{ user }}')">
|
|
||||||
Unshare
|
|
||||||
</button>
|
|
||||||
</span>
|
|
||||||
</li>
|
|
||||||
{% endfor %}
|
|
||||||
</ul>
|
|
||||||
<!-- Modal de confirmación (oculto por defecto) -->
|
|
||||||
<div class="modal fade" id="unshareModal" tabindex="-1" aria-labelledby="unshareModalLabel" aria-hidden="true">
|
|
||||||
<div class="modal-dialog modal-dialog-centered">
|
|
||||||
<div class="modal-content">
|
|
||||||
<div class="modal-header">
|
|
||||||
<h5 class="modal-title" id="unshareModalLabel">Confirm Unshare</h5>
|
|
||||||
<button type="button" class="btn-close" data-bs-dismiss="modal" aria-label="Close"></button>
|
|
||||||
</div>
|
|
||||||
<div class="modal-body">
|
|
||||||
<!-- Texto dinámico que pondremos por JS -->
|
|
||||||
<p id="unshareModalMessage"></p>
|
|
||||||
</div>
|
|
||||||
<div class="modal-footer">
|
|
||||||
<!-- Botón de confirmación -->
|
|
||||||
<button type="button" id="confirmUnshareBtn" class="btn btn-danger">Yes, Unshare</button>
|
|
||||||
<!-- Botón para cancelar/cerrar -->
|
|
||||||
<button type="button" class="btn btn-secondary" data-bs-dismiss="modal">Cancel</button>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<script>
|
|
||||||
// Variables globales para guardar pasteId y username a descompartir
|
|
||||||
let unsharePasteId = null;
|
|
||||||
let unshareUsername = null;
|
|
||||||
|
|
||||||
function showUnshareModal(pasteId, username) {
|
|
||||||
unsharePasteId = pasteId;
|
|
||||||
unshareUsername = username;
|
|
||||||
|
|
||||||
// Cambiar el texto que aparece en el modal
|
|
||||||
const messageElem = document.getElementById('unshareModalMessage');
|
|
||||||
messageElem.textContent = `Are you sure you want to remove access for "${username}"?`;
|
|
||||||
|
|
||||||
// Mostrar el modal
|
|
||||||
const modalElement = document.getElementById('unshareModal');
|
|
||||||
const modalInstance = new bootstrap.Modal(modalElement);
|
|
||||||
modalInstance.show();
|
|
||||||
}
|
|
||||||
|
|
||||||
// Botón “Yes, Unshare” dentro del modal
|
|
||||||
document.getElementById('confirmUnshareBtn').addEventListener('click', function () {
|
|
||||||
fetch(`/paste/${unsharePasteId}/unshare`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ "username": unshareUsername })
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
// Cerrar el modal
|
|
||||||
const modalElement = document.getElementById('unshareModal');
|
|
||||||
const modalInstance = bootstrap.Modal.getInstance(modalElement);
|
|
||||||
modalInstance.hide();
|
|
||||||
|
|
||||||
// Mostrar resultado en un toast
|
|
||||||
if (data.message) {
|
|
||||||
showToast(data.message, 'bg-success');
|
|
||||||
} else if (data.error) {
|
|
||||||
showToast(data.error, 'bg-danger');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recargar la página o eliminar el <li> para ese usuario
|
|
||||||
location.reload();
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
showToast('Error while unsharing paste.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
{% endif %}
|
|
||||||
</div>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
||||||
{% block scripts %}
|
|
||||||
<script>
|
|
||||||
document.addEventListener('DOMContentLoaded', function () {
|
|
||||||
// Funcionalidad de Compartir
|
|
||||||
const shareUsernameInput = document.getElementById('share-username');
|
|
||||||
const suggestionsBox = document.getElementById('user-suggestions');
|
|
||||||
const shareSubmitButton = document.getElementById('share-submit');
|
|
||||||
|
|
||||||
if (shareUsernameInput && suggestionsBox && shareSubmitButton) {
|
|
||||||
// Función para buscar usuarios
|
|
||||||
async function fetchUsers(query) {
|
|
||||||
try {
|
|
||||||
const response = await fetch(`/api/users/search?q=${encodeURIComponent(query)}`);
|
|
||||||
const users = await response.json();
|
|
||||||
return users;
|
|
||||||
} catch (error) {
|
|
||||||
console.error('Error fetching users:', error);
|
|
||||||
return [];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// Mostrar sugerencias
|
|
||||||
function showSuggestions(users) {
|
|
||||||
suggestionsBox.innerHTML = '';
|
|
||||||
if (users.length === 0) {
|
|
||||||
suggestionsBox.classList.add('d-none');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
users.forEach(user => {
|
|
||||||
const item = document.createElement('button');
|
|
||||||
item.type = 'button';
|
|
||||||
item.classList.add('list-group-item', 'list-group-item-action');
|
|
||||||
item.textContent = user.username;
|
|
||||||
item.addEventListener('click', () => {
|
|
||||||
shareUsernameInput.value = user.username;
|
|
||||||
suggestionsBox.classList.add('d-none');
|
|
||||||
});
|
|
||||||
suggestionsBox.appendChild(item);
|
|
||||||
});
|
|
||||||
|
|
||||||
suggestionsBox.classList.remove('d-none');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Evento de entrada
|
|
||||||
shareUsernameInput.addEventListener('input', async function () {
|
|
||||||
const query = this.value.trim();
|
|
||||||
if (query.length >= 2) { // Solo buscar si hay al menos 2 caracteres
|
|
||||||
const users = await fetchUsers(query);
|
|
||||||
showSuggestions(users);
|
|
||||||
} else {
|
|
||||||
suggestionsBox.classList.add('d-none');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Ocultar sugerencias si se hace clic fuera del input
|
|
||||||
document.addEventListener('click', function (event) {
|
|
||||||
if (!shareUsernameInput.contains(event.target) && !suggestionsBox.contains(event.target)) {
|
|
||||||
suggestionsBox.classList.add('d-none');
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
// Event listener para el botón de compartir
|
|
||||||
shareSubmitButton.addEventListener('click', () => {
|
|
||||||
const username = shareUsernameInput.value.trim();
|
|
||||||
const canEdit = document.getElementById('share-can-edit').checked;
|
|
||||||
|
|
||||||
if (!username) {
|
|
||||||
showToast('Por favor, ingresa un nombre de usuario.', 'bg-warning');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
fetch(`/paste/{{ paste.id }}/share`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json',
|
|
||||||
},
|
|
||||||
credentials: 'include',
|
|
||||||
body: JSON.stringify({ username, can_edit: canEdit })
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.message) {
|
|
||||||
showToast(data.message, 'bg-success');
|
|
||||||
const shareModal = bootstrap.Modal.getInstance(document.getElementById('shareModal'));
|
|
||||||
shareModal?.hide();
|
|
||||||
// Limpia campos
|
|
||||||
shareUsernameInput.value = '';
|
|
||||||
document.getElementById('share-can-edit').checked = true;
|
|
||||||
} else if (data.error) {
|
|
||||||
showToast(data.error, 'bg-danger');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error sharing paste:', error);
|
|
||||||
showToast('Error sharing paste.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Funcionalidad de Favoritos
|
|
||||||
const favoriteButton = document.getElementById('favorite-button');
|
|
||||||
if (favoriteButton) {
|
|
||||||
favoriteButton.addEventListener('click', function () {
|
|
||||||
const action = "{{ 'unfavorite' if paste in current_user.favorite_pastes else 'favorite' }}";
|
|
||||||
const url = `/paste/{{ paste.id }}/${action}`;
|
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include'
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.message.includes('added')) {
|
|
||||||
favoriteButton.innerHTML = '❤️ Remove from Favorites';
|
|
||||||
} else {
|
|
||||||
favoriteButton.innerHTML = '❤️ Add to Favorites';
|
|
||||||
}
|
|
||||||
if (data.success) {
|
|
||||||
showToast(data.message, 'bg-success');
|
|
||||||
} else {
|
|
||||||
showToast(data.message || 'Error updating favorites.', 'bg-danger');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error updating favorites:', error);
|
|
||||||
showToast('Error updating favorites.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Funcionalidad de Toggle Editable
|
|
||||||
{% if can_edit and paste.editable %}
|
|
||||||
const toggleEditableButton = document.getElementById('toggle-editable-button');
|
|
||||||
if (toggleEditableButton) {
|
|
||||||
toggleEditableButton.addEventListener('click', function() {
|
|
||||||
const url = `/paste/{{ paste.id }}/toggle_editable`;
|
|
||||||
|
|
||||||
fetch(url, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: {
|
|
||||||
'Content-Type': 'application/json'
|
|
||||||
},
|
|
||||||
credentials: 'include'
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
if (data.success) {
|
|
||||||
if (data.editable) {
|
|
||||||
toggleEditableButton.innerHTML = 'Disable Editable';
|
|
||||||
toggleEditableButton.classList.remove('btn-success');
|
|
||||||
toggleEditableButton.classList.add('btn-warning');
|
|
||||||
const editButton = document.getElementById('edit-button');
|
|
||||||
if (editButton) editButton.style.display = 'inline-block';
|
|
||||||
} else {
|
|
||||||
toggleEditableButton.innerHTML = 'Enable Editable';
|
|
||||||
toggleEditableButton.classList.remove('btn-warning');
|
|
||||||
toggleEditableButton.classList.add('btn-success');
|
|
||||||
const editButton = document.getElementById('edit-button');
|
|
||||||
if (editButton) editButton.style.display = 'none';
|
|
||||||
}
|
|
||||||
showToast(data.message, 'bg-success');
|
|
||||||
} else {
|
|
||||||
showToast(data.error || 'Action failed', 'bg-danger');
|
|
||||||
}
|
|
||||||
})
|
|
||||||
.catch(error => {
|
|
||||||
console.error('Error updating editable:', error);
|
|
||||||
showToast('Error updating editable.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
// Funcionalidad de Copiar al Portapapeles (si NO es Markdown)
|
|
||||||
{% if not is_markdown %}
|
|
||||||
const copyButton = document.getElementById('copy-button');
|
|
||||||
if (copyButton) {
|
|
||||||
copyButton.addEventListener('click', function () {
|
|
||||||
const codeElement = document.querySelector('.highlight code');
|
|
||||||
if (!codeElement) {
|
|
||||||
showToast('Error: code snippet not found.', 'bg-danger');
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
|
|
||||||
let code = codeElement.innerText.replace(/^\s*\d+\s/gm, '').trim();
|
|
||||||
|
|
||||||
navigator.clipboard.writeText(code)
|
|
||||||
.then(() => {
|
|
||||||
showToast('¡Copied to clipboard!', 'bg-success');
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error('Error copying to clipboard:', err);
|
|
||||||
showToast('Error copying code.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
{% endif %}
|
|
||||||
|
|
||||||
// Funcionalidad del Selector de Estilos de Pygments
|
|
||||||
const pygmentsStyleSelector = document.getElementById('pygments-style');
|
|
||||||
if (pygmentsStyleSelector) {
|
|
||||||
pygmentsStyleSelector.addEventListener('change', function () {
|
|
||||||
const selectedStyle = this.value;
|
|
||||||
document.querySelectorAll('.highlight code').forEach(function (codeElement) {
|
|
||||||
// Remover clases relacionadas con estilos anteriores
|
|
||||||
[...codeElement.classList].forEach(cls => {
|
|
||||||
if (cls.startsWith('bg-') || cls.startsWith('hljs-') || cls.startsWith('theme-')) {
|
|
||||||
codeElement.classList.remove(cls);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
// Añadir la clase del estilo seleccionado
|
|
||||||
codeElement.classList.add(selectedStyle);
|
|
||||||
});
|
|
||||||
showToast('Pygments style changed locally.', 'bg-success');
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
// Funcionalidad de Unshare Modal
|
|
||||||
const confirmUnshareBtn = document.getElementById('confirmUnshareBtn');
|
|
||||||
if (confirmUnshareBtn) {
|
|
||||||
let unsharePasteId = null;
|
|
||||||
let unshareUsername = null;
|
|
||||||
|
|
||||||
confirmUnshareBtn.addEventListener('click', function () {
|
|
||||||
fetch(`/paste/${unsharePasteId}/unshare`, {
|
|
||||||
method: 'POST',
|
|
||||||
headers: { 'Content-Type': 'application/json' },
|
|
||||||
body: JSON.stringify({ "username": unshareUsername })
|
|
||||||
})
|
|
||||||
.then(response => response.json())
|
|
||||||
.then(data => {
|
|
||||||
// Cerrar el modal
|
|
||||||
const modalElement = document.getElementById('unshareModal');
|
|
||||||
const modalInstance = bootstrap.Modal.getInstance(modalElement);
|
|
||||||
modalInstance.hide();
|
|
||||||
|
|
||||||
// Mostrar resultado en un toast
|
|
||||||
if (data.message) {
|
|
||||||
showToast(data.message, 'bg-success');
|
|
||||||
} else if (data.error) {
|
|
||||||
showToast(data.error, 'bg-danger');
|
|
||||||
}
|
|
||||||
|
|
||||||
// Recargar la página o eliminar el <li> para ese usuario
|
|
||||||
location.reload();
|
|
||||||
})
|
|
||||||
.catch(err => {
|
|
||||||
console.error(err);
|
|
||||||
showToast('Error sharing paste.', 'bg-danger');
|
|
||||||
});
|
|
||||||
});
|
|
||||||
}
|
|
||||||
});
|
|
||||||
</script>
|
|
||||||
{% endblock %}
|
|
||||||
|
|
Loading…
x
Reference in New Issue
Block a user