|
import { api } from '../api.js';
|
|
|
|
class FilePreview extends HTMLElement {
|
|
constructor() {
|
|
super();
|
|
this.file = null;
|
|
this.handleEscape = this.handleEscape.bind(this);
|
|
}
|
|
|
|
connectedCallback() {
|
|
this.render();
|
|
this.setupEventListeners();
|
|
}
|
|
|
|
setupEventListeners() {
|
|
const closeBtn = this.querySelector('.close-preview');
|
|
const downloadBtn = this.querySelector('.download-btn');
|
|
const shareBtn = this.querySelector('.share-btn');
|
|
|
|
if (closeBtn) {
|
|
closeBtn.addEventListener('click', () => this.close());
|
|
}
|
|
|
|
if (downloadBtn) {
|
|
downloadBtn.addEventListener('click', () => this.downloadFile());
|
|
}
|
|
|
|
if (shareBtn) {
|
|
shareBtn.addEventListener('click', () => this.shareFile());
|
|
}
|
|
}
|
|
|
|
handleEscape(e) {
|
|
if (e.key === 'Escape' && this.style.display === 'block') {
|
|
this.close();
|
|
}
|
|
}
|
|
|
|
async show(file, pushState = true) {
|
|
this.file = file;
|
|
this.style.display = 'block';
|
|
document.addEventListener('keydown', this.handleEscape);
|
|
this.renderPreview();
|
|
}
|
|
|
|
close() {
|
|
window.history.back();
|
|
}
|
|
|
|
hide() {
|
|
this.style.display = 'none';
|
|
this.file = null;
|
|
document.removeEventListener('keydown', this.handleEscape);
|
|
this.remove();
|
|
}
|
|
|
|
async renderPreview() {
|
|
const previewContent = this.querySelector('.preview-content');
|
|
const fileName = this.querySelector('.preview-file-name');
|
|
const fileInfo = this.querySelector('.preview-file-info');
|
|
|
|
fileName.textContent = this.file.name;
|
|
fileInfo.textContent = `${this.formatFileSize(this.file.size)} • ${new Date(this.file.created_at).toLocaleDateString()}`;
|
|
|
|
if (this.file.mime_type.startsWith('image/')) {
|
|
previewContent.innerHTML = `<img alt="${this.file.name}">`;
|
|
this.loadAuthenticatedMedia(previewContent.querySelector('img'));
|
|
} else if (this.file.mime_type.startsWith('video/')) {
|
|
previewContent.innerHTML = `
|
|
<video controls>
|
|
Your browser does not support the video tag.
|
|
</video>
|
|
`;
|
|
this.loadAuthenticatedMedia(previewContent.querySelector('video'));
|
|
} else if (this.file.mime_type.startsWith('audio/')) {
|
|
previewContent.innerHTML = `
|
|
<audio controls>
|
|
Your browser does not support the audio tag.
|
|
</audio>
|
|
`;
|
|
this.loadAuthenticatedMedia(previewContent.querySelector('audio'));
|
|
} else if (this.file.mime_type === 'application/pdf') {
|
|
previewContent.innerHTML = `<iframe type="application/pdf"></iframe>`;
|
|
this.loadAuthenticatedMedia(previewContent.querySelector('iframe'));
|
|
} else if (this.file.mime_type.startsWith('text/')) {
|
|
this.loadTextPreview(previewContent);
|
|
} else {
|
|
previewContent.innerHTML = `
|
|
<div class="no-preview">
|
|
<p>Preview not available for this file type</p>
|
|
<button class="btn btn-primary" onclick="this.getRootNode().host.downloadFile()">Download File</button>
|
|
</div>
|
|
`;
|
|
}
|
|
}
|
|
|
|
async loadAuthenticatedMedia(element) {
|
|
try {
|
|
const blob = await api.downloadFile(this.file.id);
|
|
const url = URL.createObjectURL(blob);
|
|
element.src = url;
|
|
} catch (error) {
|
|
console.error('Failed to load media:', error);
|
|
element.parentElement.innerHTML = '<p>Failed to load preview</p>';
|
|
}
|
|
}
|
|
|
|
async loadTextPreview(container) {
|
|
try {
|
|
const blob = await api.downloadFile(this.file.id);
|
|
const text = await blob.text();
|
|
container.innerHTML = `<pre>${this.escapeHtml(text)}</pre>`;
|
|
} catch (error) {
|
|
container.innerHTML = '<p>Failed to load preview</p>';
|
|
}
|
|
}
|
|
|
|
async downloadFile() {
|
|
try {
|
|
const blob = await api.downloadFile(this.file.id);
|
|
const url = window.URL.createObjectURL(blob);
|
|
const a = document.createElement('a');
|
|
a.href = url;
|
|
a.download = this.file.name;
|
|
document.body.appendChild(a);
|
|
a.click();
|
|
window.URL.revokeObjectURL(url);
|
|
document.body.removeChild(a);
|
|
} catch (error) {
|
|
console.error('Failed to download file:', error);
|
|
}
|
|
}
|
|
|
|
shareFile() {
|
|
this.dispatchEvent(new CustomEvent('share-file', {
|
|
detail: { file: this.file },
|
|
bubbles: true
|
|
}));
|
|
}
|
|
|
|
formatFileSize(bytes) {
|
|
const units = ['B', 'KB', 'MB', 'GB'];
|
|
let size = bytes;
|
|
let unitIndex = 0;
|
|
while (size >= 1024 && unitIndex < units.length - 1) {
|
|
size /= 1024;
|
|
unitIndex++;
|
|
}
|
|
return `${size.toFixed(1)} ${units[unitIndex]}`;
|
|
}
|
|
|
|
escapeHtml(text) {
|
|
const div = document.createElement('div');
|
|
div.textContent = text;
|
|
return div.innerHTML;
|
|
}
|
|
|
|
render() {
|
|
this.innerHTML = `
|
|
<div class="file-preview-overlay">
|
|
<div class="file-preview-header">
|
|
<div class="header-left">
|
|
<button class="button close-preview">Back</button>
|
|
<div class="preview-info">
|
|
<h2 class="preview-file-name"></h2>
|
|
<p class="preview-file-info"></p>
|
|
</div>
|
|
</div>
|
|
<div class="preview-actions">
|
|
<button class="button download-btn">Download</button>
|
|
<button class="button share-btn">Share</button>
|
|
</div>
|
|
</div>
|
|
<div class="preview-content"></div>
|
|
</div>
|
|
`;
|
|
this.style.display = 'none';
|
|
}
|
|
}
|
|
|
|
customElements.define('file-preview', FilePreview);
|
|
export { FilePreview };
|